yading@11: /* yading@11: * Raw TAK demuxer yading@11: * Copyright (c) 2012 Paul B Mahol yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: #include "libavcodec/tak.h" yading@11: #include "avformat.h" yading@11: #include "internal.h" yading@11: #include "rawdec.h" yading@11: #include "apetag.h" yading@11: yading@11: typedef struct TAKDemuxContext { yading@11: int mlast_frame; yading@11: int64_t data_end; yading@11: } TAKDemuxContext; yading@11: yading@11: static int tak_probe(AVProbeData *p) yading@11: { yading@11: if (!memcmp(p->buf, "tBaK", 4)) yading@11: return AVPROBE_SCORE_MAX / 2; yading@11: return 0; yading@11: } yading@11: yading@11: static int tak_read_header(AVFormatContext *s) yading@11: { yading@11: TAKDemuxContext *tc = s->priv_data; yading@11: AVIOContext *pb = s->pb; yading@11: GetBitContext gb; yading@11: AVStream *st; yading@11: uint8_t *buffer = NULL; yading@11: int ret; yading@11: yading@11: st = avformat_new_stream(s, 0); yading@11: if (!st) yading@11: return AVERROR(ENOMEM); yading@11: yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_id = AV_CODEC_ID_TAK; yading@11: st->need_parsing = AVSTREAM_PARSE_FULL_RAW; yading@11: yading@11: tc->mlast_frame = 0; yading@11: if (avio_rl32(pb) != MKTAG('t', 'B', 'a', 'K')) { yading@11: avio_seek(pb, -4, SEEK_CUR); yading@11: return 0; yading@11: } yading@11: yading@11: while (!url_feof(pb)) { yading@11: enum TAKMetaDataType type; yading@11: int size; yading@11: yading@11: type = avio_r8(pb) & 0x7f; yading@11: size = avio_rl24(pb); yading@11: yading@11: switch (type) { yading@11: case TAK_METADATA_STREAMINFO: yading@11: case TAK_METADATA_LAST_FRAME: yading@11: case TAK_METADATA_ENCODER: yading@11: buffer = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); yading@11: if (!buffer) yading@11: return AVERROR(ENOMEM); yading@11: yading@11: if (avio_read(pb, buffer, size) != size) { yading@11: av_freep(&buffer); yading@11: return AVERROR(EIO); yading@11: } yading@11: yading@11: init_get_bits(&gb, buffer, size * 8); yading@11: break; yading@11: case TAK_METADATA_MD5: { yading@11: uint8_t md5[16]; yading@11: int i; yading@11: yading@11: if (size != 19) yading@11: return AVERROR_INVALIDDATA; yading@11: avio_read(pb, md5, 16); yading@11: avio_skip(pb, 3); yading@11: av_log(s, AV_LOG_VERBOSE, "MD5="); yading@11: for (i = 0; i < 16; i++) yading@11: av_log(s, AV_LOG_VERBOSE, "%02x", md5[i]); yading@11: av_log(s, AV_LOG_VERBOSE, "\n"); yading@11: break; yading@11: } yading@11: case TAK_METADATA_END: { yading@11: int64_t curpos = avio_tell(pb); yading@11: yading@11: if (pb->seekable) { yading@11: ff_ape_parse_tag(s); yading@11: avio_seek(pb, curpos, SEEK_SET); yading@11: } yading@11: yading@11: tc->data_end += curpos; yading@11: return 0; yading@11: } yading@11: default: yading@11: ret = avio_skip(pb, size); yading@11: if (ret < 0) yading@11: return ret; yading@11: } yading@11: yading@11: if (type == TAK_METADATA_STREAMINFO) { yading@11: TAKStreamInfo ti; yading@11: yading@11: avpriv_tak_parse_streaminfo(&gb, &ti); yading@11: if (ti.samples > 0) yading@11: st->duration = ti.samples; yading@11: st->codec->bits_per_coded_sample = ti.bps; yading@11: if (ti.ch_layout) yading@11: st->codec->channel_layout = ti.ch_layout; yading@11: st->codec->sample_rate = ti.sample_rate; yading@11: st->codec->channels = ti.channels; yading@11: st->start_time = 0; yading@11: avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); yading@11: st->codec->extradata = buffer; yading@11: st->codec->extradata_size = size; yading@11: buffer = NULL; yading@11: } else if (type == TAK_METADATA_LAST_FRAME) { yading@11: if (size != 11) yading@11: return AVERROR_INVALIDDATA; yading@11: tc->mlast_frame = 1; yading@11: tc->data_end = get_bits64(&gb, TAK_LAST_FRAME_POS_BITS) + yading@11: get_bits(&gb, TAK_LAST_FRAME_SIZE_BITS); yading@11: av_freep(&buffer); yading@11: } else if (type == TAK_METADATA_ENCODER) { yading@11: av_log(s, AV_LOG_VERBOSE, "encoder version: %0X\n", yading@11: get_bits_long(&gb, TAK_ENCODER_VERSION_BITS)); yading@11: av_freep(&buffer); yading@11: } yading@11: } yading@11: yading@11: return AVERROR_EOF; yading@11: } yading@11: yading@11: static int raw_read_packet(AVFormatContext *s, AVPacket *pkt) yading@11: { yading@11: TAKDemuxContext *tc = s->priv_data; yading@11: int ret; yading@11: yading@11: if (tc->mlast_frame) { yading@11: AVIOContext *pb = s->pb; yading@11: int64_t size, left; yading@11: yading@11: left = tc->data_end - avio_tell(s->pb); yading@11: size = FFMIN(left, 1024); yading@11: if (size <= 0) yading@11: return AVERROR_EOF; yading@11: yading@11: ret = av_get_packet(pb, pkt, size); yading@11: if (ret < 0) yading@11: return ret; yading@11: yading@11: pkt->stream_index = 0; yading@11: } else { yading@11: ret = ff_raw_read_partial_packet(s, pkt); yading@11: } yading@11: yading@11: return ret; yading@11: } yading@11: yading@11: AVInputFormat ff_tak_demuxer = { yading@11: .name = "tak", yading@11: .long_name = NULL_IF_CONFIG_SMALL("raw TAK"), yading@11: .priv_data_size = sizeof(TAKDemuxContext), yading@11: .read_probe = tak_probe, yading@11: .read_header = tak_read_header, yading@11: .read_packet = raw_read_packet, yading@11: .flags = AVFMT_GENERIC_INDEX, yading@11: .extensions = "tak", yading@11: .raw_codec_id = AV_CODEC_ID_TAK, yading@11: };