1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Dirac parser 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (c) 2007-2008 Marco Gerards <marco@gnu.org> 5cabdff1aSopenharmony_ci * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju@gmail.com> 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * This file is part of FFmpeg. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17cabdff1aSopenharmony_ci * Lesser General Public License for more details. 18cabdff1aSopenharmony_ci * 19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 21cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22cabdff1aSopenharmony_ci */ 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci/** 25cabdff1aSopenharmony_ci * @file 26cabdff1aSopenharmony_ci * Dirac Parser 27cabdff1aSopenharmony_ci * @author Marco Gerards <marco@gnu.org> 28cabdff1aSopenharmony_ci */ 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include <string.h> 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 33cabdff1aSopenharmony_ci#include "libavutil/mem.h" 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#include "parser.h" 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#define DIRAC_PARSE_INFO_PREFIX 0x42424344 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci/** 40cabdff1aSopenharmony_ci * Find the end of the current frame in the bitstream. 41cabdff1aSopenharmony_ci * @return the position of the first byte of the next frame or -1 42cabdff1aSopenharmony_ci */ 43cabdff1aSopenharmony_citypedef struct DiracParseContext { 44cabdff1aSopenharmony_ci int state; 45cabdff1aSopenharmony_ci int is_synced; 46cabdff1aSopenharmony_ci int sync_offset; 47cabdff1aSopenharmony_ci int header_bytes_needed; 48cabdff1aSopenharmony_ci int overread_index; 49cabdff1aSopenharmony_ci int buffer_size; 50cabdff1aSopenharmony_ci int index; 51cabdff1aSopenharmony_ci uint8_t *buffer; 52cabdff1aSopenharmony_ci int dirac_unit_size; 53cabdff1aSopenharmony_ci uint8_t *dirac_unit; 54cabdff1aSopenharmony_ci} DiracParseContext; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_cistatic int find_frame_end(DiracParseContext *pc, 57cabdff1aSopenharmony_ci const uint8_t *buf, int buf_size) 58cabdff1aSopenharmony_ci{ 59cabdff1aSopenharmony_ci uint32_t state = pc->state; 60cabdff1aSopenharmony_ci int i = 0; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci if (!pc->is_synced) { 63cabdff1aSopenharmony_ci for (i = 0; i < buf_size; i++) { 64cabdff1aSopenharmony_ci state = (state << 8) | buf[i]; 65cabdff1aSopenharmony_ci if (state == DIRAC_PARSE_INFO_PREFIX) { 66cabdff1aSopenharmony_ci state = -1; 67cabdff1aSopenharmony_ci pc->is_synced = 1; 68cabdff1aSopenharmony_ci pc->header_bytes_needed = 9; 69cabdff1aSopenharmony_ci pc->sync_offset = i; 70cabdff1aSopenharmony_ci break; 71cabdff1aSopenharmony_ci } 72cabdff1aSopenharmony_ci } 73cabdff1aSopenharmony_ci } 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci if (pc->is_synced) { 76cabdff1aSopenharmony_ci pc->sync_offset = 0; 77cabdff1aSopenharmony_ci for (; i < buf_size; i++) { 78cabdff1aSopenharmony_ci if (state == DIRAC_PARSE_INFO_PREFIX) { 79cabdff1aSopenharmony_ci if ((buf_size - i) >= pc->header_bytes_needed) { 80cabdff1aSopenharmony_ci pc->state = -1; 81cabdff1aSopenharmony_ci return i + pc->header_bytes_needed; 82cabdff1aSopenharmony_ci } else { 83cabdff1aSopenharmony_ci pc->header_bytes_needed = 9 - (buf_size - i); 84cabdff1aSopenharmony_ci break; 85cabdff1aSopenharmony_ci } 86cabdff1aSopenharmony_ci } else 87cabdff1aSopenharmony_ci state = (state << 8) | buf[i]; 88cabdff1aSopenharmony_ci } 89cabdff1aSopenharmony_ci } 90cabdff1aSopenharmony_ci pc->state = state; 91cabdff1aSopenharmony_ci return -1; 92cabdff1aSopenharmony_ci} 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_citypedef struct DiracParseUnit { 95cabdff1aSopenharmony_ci int next_pu_offset; 96cabdff1aSopenharmony_ci int prev_pu_offset; 97cabdff1aSopenharmony_ci uint8_t pu_type; 98cabdff1aSopenharmony_ci} DiracParseUnit; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_cistatic int unpack_parse_unit(DiracParseUnit *pu, DiracParseContext *pc, 101cabdff1aSopenharmony_ci int offset) 102cabdff1aSopenharmony_ci{ 103cabdff1aSopenharmony_ci int i; 104cabdff1aSopenharmony_ci int8_t *start; 105cabdff1aSopenharmony_ci static const uint8_t valid_pu_types[] = { 106cabdff1aSopenharmony_ci 0x00, 0x10, 0x20, 0x30, 0x08, 0x48, 0xC8, 0xE8, 0x0A, 0x0C, 0x0D, 0x0E, 107cabdff1aSopenharmony_ci 0x4C, 0x09, 0xCC, 0x88, 0xCB 108cabdff1aSopenharmony_ci }; 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci if (offset < 0 || pc->index - 13 < offset) 111cabdff1aSopenharmony_ci return 0; 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci start = pc->buffer + offset; 114cabdff1aSopenharmony_ci pu->pu_type = start[4]; 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_ci pu->next_pu_offset = AV_RB32(start + 5); 117cabdff1aSopenharmony_ci pu->prev_pu_offset = AV_RB32(start + 9); 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci /* Check for valid parse code */ 120cabdff1aSopenharmony_ci for (i = 0; i < 17; i++) 121cabdff1aSopenharmony_ci if (valid_pu_types[i] == pu->pu_type) 122cabdff1aSopenharmony_ci break; 123cabdff1aSopenharmony_ci if (i == 17) 124cabdff1aSopenharmony_ci return 0; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci if (pu->pu_type == 0x10 && pu->next_pu_offset == 0x00) 127cabdff1aSopenharmony_ci pu->next_pu_offset = 13; /* The length of a parse info header */ 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci /* Check if the parse offsets are somewhat sane */ 130cabdff1aSopenharmony_ci if ((pu->next_pu_offset && pu->next_pu_offset < 13) || 131cabdff1aSopenharmony_ci (pu->prev_pu_offset && pu->prev_pu_offset < 13)) 132cabdff1aSopenharmony_ci return 0; 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ci return 1; 135cabdff1aSopenharmony_ci} 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_cistatic int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx, 138cabdff1aSopenharmony_ci int next, const uint8_t **buf, int *buf_size) 139cabdff1aSopenharmony_ci{ 140cabdff1aSopenharmony_ci int parse_timing_info = (s->pts == AV_NOPTS_VALUE && 141cabdff1aSopenharmony_ci s->dts == AV_NOPTS_VALUE); 142cabdff1aSopenharmony_ci DiracParseContext *pc = s->priv_data; 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci if (pc->overread_index) { 145cabdff1aSopenharmony_ci memmove(pc->buffer, pc->buffer + pc->overread_index, 146cabdff1aSopenharmony_ci pc->index - pc->overread_index); 147cabdff1aSopenharmony_ci pc->index -= pc->overread_index; 148cabdff1aSopenharmony_ci pc->overread_index = 0; 149cabdff1aSopenharmony_ci if (*buf_size == 0 && pc->buffer[4] == 0x10) { 150cabdff1aSopenharmony_ci *buf = pc->buffer; 151cabdff1aSopenharmony_ci *buf_size = pc->index; 152cabdff1aSopenharmony_ci return 0; 153cabdff1aSopenharmony_ci } 154cabdff1aSopenharmony_ci } 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci if (next == -1) { 157cabdff1aSopenharmony_ci /* Found a possible frame start but not a frame end */ 158cabdff1aSopenharmony_ci void *new_buffer = 159cabdff1aSopenharmony_ci av_fast_realloc(pc->buffer, &pc->buffer_size, 160cabdff1aSopenharmony_ci pc->index + (*buf_size - pc->sync_offset)); 161cabdff1aSopenharmony_ci if (!new_buffer) 162cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 163cabdff1aSopenharmony_ci pc->buffer = new_buffer; 164cabdff1aSopenharmony_ci memcpy(pc->buffer + pc->index, (*buf + pc->sync_offset), 165cabdff1aSopenharmony_ci *buf_size - pc->sync_offset); 166cabdff1aSopenharmony_ci pc->index += *buf_size - pc->sync_offset; 167cabdff1aSopenharmony_ci return -1; 168cabdff1aSopenharmony_ci } else { 169cabdff1aSopenharmony_ci /* Found a possible frame start and a possible frame end */ 170cabdff1aSopenharmony_ci DiracParseUnit pu1, pu; 171cabdff1aSopenharmony_ci void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, 172cabdff1aSopenharmony_ci pc->index + next); 173cabdff1aSopenharmony_ci if (!new_buffer) 174cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 175cabdff1aSopenharmony_ci pc->buffer = new_buffer; 176cabdff1aSopenharmony_ci memcpy(pc->buffer + pc->index, *buf, next); 177cabdff1aSopenharmony_ci pc->index += next; 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci /* Need to check if we have a valid Parse Unit. We can't go by the 180cabdff1aSopenharmony_ci * sync pattern 'BBCD' alone because arithmetic coding of the residual 181cabdff1aSopenharmony_ci * and motion data can cause the pattern triggering a false start of 182cabdff1aSopenharmony_ci * frame. So check if the previous parse offset of the next parse unit 183cabdff1aSopenharmony_ci * is equal to the next parse offset of the current parse unit then 184cabdff1aSopenharmony_ci * we can be pretty sure that we have a valid parse unit */ 185cabdff1aSopenharmony_ci if (!unpack_parse_unit(&pu1, pc, pc->index - 13) || 186cabdff1aSopenharmony_ci !unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) || 187cabdff1aSopenharmony_ci pu.next_pu_offset != pu1.prev_pu_offset || 188cabdff1aSopenharmony_ci pc->index < pc->dirac_unit_size + 13LL + pu1.prev_pu_offset 189cabdff1aSopenharmony_ci ) { 190cabdff1aSopenharmony_ci pc->index -= 9; 191cabdff1aSopenharmony_ci *buf_size = next - 9; 192cabdff1aSopenharmony_ci pc->header_bytes_needed = 9; 193cabdff1aSopenharmony_ci return -1; 194cabdff1aSopenharmony_ci } 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci /* All non-frame data must be accompanied by frame data. This is to 197cabdff1aSopenharmony_ci * ensure that pts is set correctly. So if the current parse unit is 198cabdff1aSopenharmony_ci * not frame data, wait for frame data to come along */ 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci pc->dirac_unit = pc->buffer + pc->index - 13 - 201cabdff1aSopenharmony_ci pu1.prev_pu_offset - pc->dirac_unit_size; 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci pc->dirac_unit_size += pu.next_pu_offset; 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci if ((pu.pu_type & 0x08) != 0x08) { 206cabdff1aSopenharmony_ci pc->header_bytes_needed = 9; 207cabdff1aSopenharmony_ci *buf_size = next; 208cabdff1aSopenharmony_ci return -1; 209cabdff1aSopenharmony_ci } 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci /* Get the picture number to set the pts and dts*/ 212cabdff1aSopenharmony_ci if (parse_timing_info && pu1.prev_pu_offset >= 13) { 213cabdff1aSopenharmony_ci uint8_t *cur_pu = pc->buffer + 214cabdff1aSopenharmony_ci pc->index - 13 - pu1.prev_pu_offset; 215cabdff1aSopenharmony_ci int64_t pts = AV_RB32(cur_pu + 13); 216cabdff1aSopenharmony_ci if (s->last_pts == 0 && s->last_dts == 0) 217cabdff1aSopenharmony_ci s->dts = pts - 1; 218cabdff1aSopenharmony_ci else if (s->last_dts != AV_NOPTS_VALUE) 219cabdff1aSopenharmony_ci s->dts = s->last_dts + 1; 220cabdff1aSopenharmony_ci s->pts = pts; 221cabdff1aSopenharmony_ci if (!avctx->has_b_frames && (cur_pu[4] & 0x03)) 222cabdff1aSopenharmony_ci avctx->has_b_frames = 1; 223cabdff1aSopenharmony_ci } 224cabdff1aSopenharmony_ci if (avctx->has_b_frames && s->pts == s->dts) 225cabdff1aSopenharmony_ci s->pict_type = AV_PICTURE_TYPE_B; 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci /* Finally have a complete Dirac data unit */ 228cabdff1aSopenharmony_ci *buf = pc->dirac_unit; 229cabdff1aSopenharmony_ci *buf_size = pc->dirac_unit_size; 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci pc->dirac_unit_size = 0; 232cabdff1aSopenharmony_ci pc->overread_index = pc->index - 13; 233cabdff1aSopenharmony_ci pc->header_bytes_needed = 9; 234cabdff1aSopenharmony_ci } 235cabdff1aSopenharmony_ci return next; 236cabdff1aSopenharmony_ci} 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_cistatic int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx, 239cabdff1aSopenharmony_ci const uint8_t **poutbuf, int *poutbuf_size, 240cabdff1aSopenharmony_ci const uint8_t *buf, int buf_size) 241cabdff1aSopenharmony_ci{ 242cabdff1aSopenharmony_ci DiracParseContext *pc = s->priv_data; 243cabdff1aSopenharmony_ci int next; 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci *poutbuf = NULL; 246cabdff1aSopenharmony_ci *poutbuf_size = 0; 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { 249cabdff1aSopenharmony_ci next = buf_size; 250cabdff1aSopenharmony_ci *poutbuf = buf; 251cabdff1aSopenharmony_ci *poutbuf_size = buf_size; 252cabdff1aSopenharmony_ci /* Assume that data has been packetized into an encapsulation unit. */ 253cabdff1aSopenharmony_ci } else { 254cabdff1aSopenharmony_ci next = find_frame_end(pc, buf, buf_size); 255cabdff1aSopenharmony_ci if (!pc->is_synced && next == -1) 256cabdff1aSopenharmony_ci /* No frame start found yet. So throw away the entire buffer. */ 257cabdff1aSopenharmony_ci return buf_size; 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci if (dirac_combine_frame(s, avctx, next, &buf, &buf_size) < 0) 260cabdff1aSopenharmony_ci return buf_size; 261cabdff1aSopenharmony_ci } 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_ci *poutbuf = buf; 264cabdff1aSopenharmony_ci *poutbuf_size = buf_size; 265cabdff1aSopenharmony_ci return next; 266cabdff1aSopenharmony_ci} 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_cistatic void dirac_parse_close(AVCodecParserContext *s) 269cabdff1aSopenharmony_ci{ 270cabdff1aSopenharmony_ci DiracParseContext *pc = s->priv_data; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci if (pc->buffer_size > 0) 273cabdff1aSopenharmony_ci av_freep(&pc->buffer); 274cabdff1aSopenharmony_ci} 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_ciconst AVCodecParser ff_dirac_parser = { 277cabdff1aSopenharmony_ci .codec_ids = { AV_CODEC_ID_DIRAC }, 278cabdff1aSopenharmony_ci .priv_data_size = sizeof(DiracParseContext), 279cabdff1aSopenharmony_ci .parser_parse = dirac_parse, 280cabdff1aSopenharmony_ci .parser_close = dirac_parse_close, 281cabdff1aSopenharmony_ci}; 282