00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavcodec/get_bits.h"
00023 #include "avformat.h"
00024 #include "id3v1.h"
00025
00026 typedef struct {
00027 int totalframes, currentframe;
00028 } TTAContext;
00029
00030 static int tta_probe(AVProbeData *p)
00031 {
00032 const uint8_t *d = p->buf;
00033
00034 if (d[0] == 'T' && d[1] == 'T' && d[2] == 'A' && d[3] == '1')
00035 return 80;
00036 return 0;
00037 }
00038
00039 static int tta_read_header(AVFormatContext *s, AVFormatParameters *ap)
00040 {
00041 TTAContext *c = s->priv_data;
00042 AVStream *st;
00043 int i, channels, bps, samplerate, datalen, framelen;
00044 uint64_t framepos, start_offset;
00045
00046 if (!av_metadata_get(s->metadata, "", NULL, AV_METADATA_IGNORE_SUFFIX))
00047 ff_id3v1_read(s);
00048
00049 start_offset = avio_tell(s->pb);
00050 if (avio_rl32(s->pb) != AV_RL32("TTA1"))
00051 return -1;
00052
00053 avio_seek(s->pb, 2, SEEK_CUR);
00054 channels = avio_rl16(s->pb);
00055 bps = avio_rl16(s->pb);
00056 samplerate = avio_rl32(s->pb);
00057 if(samplerate <= 0 || samplerate > 1000000){
00058 av_log(s, AV_LOG_ERROR, "nonsense samplerate\n");
00059 return -1;
00060 }
00061
00062 datalen = avio_rl32(s->pb);
00063 if(datalen < 0){
00064 av_log(s, AV_LOG_ERROR, "nonsense datalen\n");
00065 return -1;
00066 }
00067
00068 avio_seek(s->pb, 4, SEEK_CUR);
00069
00070 framelen = samplerate*256/245;
00071 c->totalframes = datalen / framelen + ((datalen % framelen) ? 1 : 0);
00072 c->currentframe = 0;
00073
00074 if(c->totalframes >= UINT_MAX/sizeof(uint32_t)){
00075 av_log(s, AV_LOG_ERROR, "totalframes too large\n");
00076 return -1;
00077 }
00078
00079 st = av_new_stream(s, 0);
00080 if (!st)
00081 return AVERROR(ENOMEM);
00082
00083 av_set_pts_info(st, 64, 1, samplerate);
00084 st->start_time = 0;
00085 st->duration = datalen;
00086
00087 framepos = avio_tell(s->pb) + 4*c->totalframes + 4;
00088
00089 for (i = 0; i < c->totalframes; i++) {
00090 uint32_t size = avio_rl32(s->pb);
00091 av_add_index_entry(st, framepos, i*framelen, size, 0, AVINDEX_KEYFRAME);
00092 framepos += size;
00093 }
00094 avio_seek(s->pb, 4, SEEK_CUR);
00095
00096 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00097 st->codec->codec_id = CODEC_ID_TTA;
00098 st->codec->channels = channels;
00099 st->codec->sample_rate = samplerate;
00100 st->codec->bits_per_coded_sample = bps;
00101
00102 st->codec->extradata_size = avio_tell(s->pb) - start_offset;
00103 if(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){
00104
00105 av_log(s, AV_LOG_ERROR, "extradata_size too large\n");
00106 return -1;
00107 }
00108 st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
00109 avio_seek(s->pb, start_offset, SEEK_SET);
00110 avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
00111
00112 return 0;
00113 }
00114
00115 static int tta_read_packet(AVFormatContext *s, AVPacket *pkt)
00116 {
00117 TTAContext *c = s->priv_data;
00118 AVStream *st = s->streams[0];
00119 int size, ret;
00120
00121
00122 if (c->currentframe > c->totalframes)
00123 return -1;
00124
00125 size = st->index_entries[c->currentframe].size;
00126
00127 ret = av_get_packet(s->pb, pkt, size);
00128 pkt->dts = st->index_entries[c->currentframe++].timestamp;
00129 return ret;
00130 }
00131
00132 static int tta_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
00133 {
00134 TTAContext *c = s->priv_data;
00135 AVStream *st = s->streams[stream_index];
00136 int index = av_index_search_timestamp(st, timestamp, flags);
00137 if (index < 0)
00138 return -1;
00139
00140 c->currentframe = index;
00141 avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET);
00142
00143 return 0;
00144 }
00145
00146 AVInputFormat ff_tta_demuxer = {
00147 "tta",
00148 NULL_IF_CONFIG_SMALL("True Audio"),
00149 sizeof(TTAContext),
00150 tta_probe,
00151 tta_read_header,
00152 tta_read_packet,
00153 NULL,
00154 tta_read_seek,
00155 .extensions = "tta",
00156 };