1/* 2 * TAK parser 3 * Copyright (c) 2012 Michael Niedermayer 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * TAK parser 25 **/ 26 27#define BITSTREAM_READER_LE 28#include "parser.h" 29#include "tak.h" 30 31typedef struct TAKParseContext { 32 ParseContext pc; 33 TAKStreamInfo ti; 34 int index; 35} TAKParseContext; 36 37static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx, 38 const uint8_t **poutbuf, int *poutbuf_size, 39 const uint8_t *buf, int buf_size) 40{ 41 TAKParseContext *t = s->priv_data; 42 ParseContext *pc = &t->pc; 43 int next = END_NOT_FOUND; 44 GetBitContext gb; 45 int consumed = 0; 46 int needed = buf_size ? TAK_MAX_FRAME_HEADER_BYTES : 8; 47 int ret; 48 49 *poutbuf = buf; 50 *poutbuf_size = buf_size; 51 52 if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { 53 TAKStreamInfo ti; 54 if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0) 55 return buf_size; 56 if (!ff_tak_decode_frame_header(avctx, &gb, &ti, 127)) 57 s->duration = t->ti.last_frame_samples ? t->ti.last_frame_samples 58 : t->ti.frame_samples; 59 return buf_size; 60 } 61 62 while (buf_size || t->index + needed <= pc->index) { 63 if (buf_size && t->index + TAK_MAX_FRAME_HEADER_BYTES > pc->index) { 64 int tmp_buf_size = FFMIN(TAK_MAX_FRAME_HEADER_BYTES, 65 buf_size); 66 const uint8_t *tmp_buf = buf; 67 68 if (ff_combine_frame(pc, END_NOT_FOUND, &tmp_buf, &tmp_buf_size) != -1) 69 goto fail; 70 consumed += tmp_buf_size; 71 buf += tmp_buf_size; 72 buf_size -= tmp_buf_size; 73 } 74 75 for (; t->index + needed <= pc->index; t->index++) { 76 if (pc->buffer[ t->index ] == 0xFF && 77 pc->buffer[ t->index + 1 ] == 0xA0) { 78 TAKStreamInfo ti; 79 80 if ((ret = init_get_bits8(&gb, pc->buffer + t->index, 81 pc->index - t->index)) < 0) 82 goto fail; 83 if (!ff_tak_decode_frame_header(avctx, &gb, 84 pc->frame_start_found ? &ti : &t->ti, 127) && 85 !ff_tak_check_crc(pc->buffer + t->index, 86 get_bits_count(&gb) / 8)) { 87 if (!pc->frame_start_found) { 88 pc->frame_start_found = 1; 89 s->duration = t->ti.last_frame_samples ? 90 t->ti.last_frame_samples : 91 t->ti.frame_samples; 92 s->key_frame = !!(t->ti.flags & TAK_FRAME_FLAG_HAS_INFO); 93 } else { 94 pc->frame_start_found = 0; 95 next = t->index - pc->index; 96 t->index = 0; 97 goto found; 98 } 99 } 100 } 101 } 102 } 103found: 104 105 if (consumed && !buf_size && next == END_NOT_FOUND || 106 ff_combine_frame(pc, next, &buf, &buf_size) < 0) { 107 goto fail; 108 } 109 110 if (next != END_NOT_FOUND) { 111 next += consumed; 112 pc->overread = FFMAX(0, -next); 113 } 114 115 *poutbuf = buf; 116 *poutbuf_size = buf_size; 117 return next; 118 119fail: 120 *poutbuf = NULL; 121 *poutbuf_size = 0; 122 return buf_size + consumed; 123} 124 125const AVCodecParser ff_tak_parser = { 126 .codec_ids = { AV_CODEC_ID_TAK }, 127 .priv_data_size = sizeof(TAKParseContext), 128 .parser_parse = tak_parse, 129 .parser_close = ff_parse_close, 130}; 131