1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * True Audio (TTA) muxer 3cabdff1aSopenharmony_ci * Copyright (c) 2016 James Almer 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/crc.h" 23cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavcodec/packet_internal.h" 26cabdff1aSopenharmony_ci#include "apetag.h" 27cabdff1aSopenharmony_ci#include "avformat.h" 28cabdff1aSopenharmony_ci#include "avio_internal.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_citypedef struct TTAMuxContext { 32cabdff1aSopenharmony_ci AVIOContext *seek_table; 33cabdff1aSopenharmony_ci PacketList queue; 34cabdff1aSopenharmony_ci uint32_t nb_samples; 35cabdff1aSopenharmony_ci int frame_size; 36cabdff1aSopenharmony_ci int last_frame; 37cabdff1aSopenharmony_ci} TTAMuxContext; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_cistatic int tta_init(AVFormatContext *s) 40cabdff1aSopenharmony_ci{ 41cabdff1aSopenharmony_ci TTAMuxContext *tta = s->priv_data; 42cabdff1aSopenharmony_ci AVCodecParameters *par; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci if (s->nb_streams != 1) { 45cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Only one stream is supported\n"); 46cabdff1aSopenharmony_ci return AVERROR(EINVAL); 47cabdff1aSopenharmony_ci } 48cabdff1aSopenharmony_ci par = s->streams[0]->codecpar; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci if (par->codec_id != AV_CODEC_ID_TTA) { 51cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unsupported codec\n"); 52cabdff1aSopenharmony_ci return AVERROR(EINVAL); 53cabdff1aSopenharmony_ci } 54cabdff1aSopenharmony_ci if (par->extradata && par->extradata_size < 22) { 55cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Invalid TTA extradata\n"); 56cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 57cabdff1aSopenharmony_ci } 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci /* Prevent overflow */ 60cabdff1aSopenharmony_ci if (par->sample_rate > 0x7FFFFFu) { 61cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); 62cabdff1aSopenharmony_ci return AVERROR(EINVAL); 63cabdff1aSopenharmony_ci } 64cabdff1aSopenharmony_ci tta->frame_size = par->sample_rate * 256 / 245; 65cabdff1aSopenharmony_ci avpriv_set_pts_info(s->streams[0], 64, 1, par->sample_rate); 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci return 0; 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic int tta_write_header(AVFormatContext *s) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci TTAMuxContext *tta = s->priv_data; 73cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[0]->codecpar; 74cabdff1aSopenharmony_ci int ret; 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci if ((ret = avio_open_dyn_buf(&tta->seek_table)) < 0) 77cabdff1aSopenharmony_ci return ret; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci /* Ignore most extradata information if present. It can be innacurate 80cabdff1aSopenharmony_ci if for example remuxing from Matroska */ 81cabdff1aSopenharmony_ci ffio_init_checksum(s->pb, ff_crcEDB88320_update, UINT32_MAX); 82cabdff1aSopenharmony_ci ffio_init_checksum(tta->seek_table, ff_crcEDB88320_update, UINT32_MAX); 83cabdff1aSopenharmony_ci avio_write(s->pb, "TTA1", 4); 84cabdff1aSopenharmony_ci avio_wl16(s->pb, par->extradata ? AV_RL16(par->extradata + 4) : 1); 85cabdff1aSopenharmony_ci avio_wl16(s->pb, par->ch_layout.nb_channels); 86cabdff1aSopenharmony_ci avio_wl16(s->pb, par->bits_per_raw_sample); 87cabdff1aSopenharmony_ci avio_wl32(s->pb, par->sample_rate); 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci return 0; 90cabdff1aSopenharmony_ci} 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_cistatic int tta_write_packet(AVFormatContext *s, AVPacket *pkt) 93cabdff1aSopenharmony_ci{ 94cabdff1aSopenharmony_ci TTAMuxContext *tta = s->priv_data; 95cabdff1aSopenharmony_ci int ret; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci ret = avpriv_packet_list_put(&tta->queue, pkt, NULL, 0); 98cabdff1aSopenharmony_ci if (ret < 0) { 99cabdff1aSopenharmony_ci return ret; 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci pkt = &tta->queue.tail->pkt; 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci avio_wl32(tta->seek_table, pkt->size); 104cabdff1aSopenharmony_ci tta->nb_samples += pkt->duration; 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci if (tta->frame_size != pkt->duration) { 107cabdff1aSopenharmony_ci if (tta->last_frame) { 108cabdff1aSopenharmony_ci /* Two frames with a different duration than the default frame 109cabdff1aSopenharmony_ci size means the TTA stream comes from a faulty container, and 110cabdff1aSopenharmony_ci there's no way the last frame duration will be correct. */ 111cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Invalid frame durations\n"); 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci /* First frame with a different duration than the default frame size. 116cabdff1aSopenharmony_ci Assume it's the last frame in the stream and continue. */ 117cabdff1aSopenharmony_ci tta->last_frame++; 118cabdff1aSopenharmony_ci } 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci return 0; 121cabdff1aSopenharmony_ci} 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_cistatic void tta_queue_flush(AVFormatContext *s) 124cabdff1aSopenharmony_ci{ 125cabdff1aSopenharmony_ci TTAMuxContext *tta = s->priv_data; 126cabdff1aSopenharmony_ci AVPacket *const pkt = ffformatcontext(s)->pkt; 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci while (tta->queue.head) { 129cabdff1aSopenharmony_ci avpriv_packet_list_get(&tta->queue, pkt); 130cabdff1aSopenharmony_ci avio_write(s->pb, pkt->data, pkt->size); 131cabdff1aSopenharmony_ci av_packet_unref(pkt); 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci} 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_cistatic int tta_write_trailer(AVFormatContext *s) 136cabdff1aSopenharmony_ci{ 137cabdff1aSopenharmony_ci TTAMuxContext *tta = s->priv_data; 138cabdff1aSopenharmony_ci uint8_t *ptr; 139cabdff1aSopenharmony_ci unsigned int crc; 140cabdff1aSopenharmony_ci int size; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci avio_wl32(s->pb, tta->nb_samples); 143cabdff1aSopenharmony_ci crc = ffio_get_checksum(s->pb) ^ UINT32_MAX; 144cabdff1aSopenharmony_ci avio_wl32(s->pb, crc); 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci /* Write Seek table */ 147cabdff1aSopenharmony_ci crc = ffio_get_checksum(tta->seek_table) ^ UINT32_MAX; 148cabdff1aSopenharmony_ci avio_wl32(tta->seek_table, crc); 149cabdff1aSopenharmony_ci size = avio_get_dyn_buf(tta->seek_table, &ptr); 150cabdff1aSopenharmony_ci avio_write(s->pb, ptr, size); 151cabdff1aSopenharmony_ci 152cabdff1aSopenharmony_ci /* Write audio data */ 153cabdff1aSopenharmony_ci tta_queue_flush(s); 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci ff_ape_write_tag(s); 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci return 0; 158cabdff1aSopenharmony_ci} 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_cistatic void tta_deinit(AVFormatContext *s) 161cabdff1aSopenharmony_ci{ 162cabdff1aSopenharmony_ci TTAMuxContext *tta = s->priv_data; 163cabdff1aSopenharmony_ci 164cabdff1aSopenharmony_ci ffio_free_dyn_buf(&tta->seek_table); 165cabdff1aSopenharmony_ci avpriv_packet_list_free(&tta->queue); 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ciconst AVOutputFormat ff_tta_muxer = { 169cabdff1aSopenharmony_ci .name = "tta", 170cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"), 171cabdff1aSopenharmony_ci .mime_type = "audio/x-tta", 172cabdff1aSopenharmony_ci .extensions = "tta", 173cabdff1aSopenharmony_ci .priv_data_size = sizeof(TTAMuxContext), 174cabdff1aSopenharmony_ci .audio_codec = AV_CODEC_ID_TTA, 175cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_NONE, 176cabdff1aSopenharmony_ci .init = tta_init, 177cabdff1aSopenharmony_ci .deinit = tta_deinit, 178cabdff1aSopenharmony_ci .write_header = tta_write_header, 179cabdff1aSopenharmony_ci .write_packet = tta_write_packet, 180cabdff1aSopenharmony_ci .write_trailer = tta_write_trailer, 181cabdff1aSopenharmony_ci}; 182