yading@10: /* yading@10: * Audio and Video frame extraction yading@10: * Copyright (c) 2003 Fabrice Bellard yading@10: * Copyright (c) 2003 Michael Niedermayer yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "parser.h" yading@10: #include "libavutil/mem.h" yading@10: yading@10: static AVCodecParser *av_first_parser = NULL; yading@10: yading@10: AVCodecParser* av_parser_next(AVCodecParser *p){ yading@10: if(p) return p->next; yading@10: else return av_first_parser; yading@10: } yading@10: yading@10: void av_register_codec_parser(AVCodecParser *parser) yading@10: { yading@10: parser->next = av_first_parser; yading@10: av_first_parser = parser; yading@10: } yading@10: yading@10: AVCodecParserContext *av_parser_init(int codec_id) yading@10: { yading@10: AVCodecParserContext *s = NULL; yading@10: AVCodecParser *parser; yading@10: int ret; yading@10: yading@10: if(codec_id == AV_CODEC_ID_NONE) yading@10: return NULL; yading@10: yading@10: for(parser = av_first_parser; parser != NULL; parser = parser->next) { yading@10: if (parser->codec_ids[0] == codec_id || yading@10: parser->codec_ids[1] == codec_id || yading@10: parser->codec_ids[2] == codec_id || yading@10: parser->codec_ids[3] == codec_id || yading@10: parser->codec_ids[4] == codec_id) yading@10: goto found; yading@10: } yading@10: return NULL; yading@10: found: yading@10: s = av_mallocz(sizeof(AVCodecParserContext)); yading@10: if (!s) yading@10: goto err_out; yading@10: s->parser = parser; yading@10: s->priv_data = av_mallocz(parser->priv_data_size); yading@10: if (!s->priv_data) yading@10: goto err_out; yading@10: s->fetch_timestamp=1; yading@10: s->pict_type = AV_PICTURE_TYPE_I; yading@10: if (parser->parser_init) { yading@10: ret = parser->parser_init(s); yading@10: if (ret != 0) yading@10: goto err_out; yading@10: } yading@10: s->key_frame = -1; yading@10: s->convergence_duration = 0; yading@10: s->dts_sync_point = INT_MIN; yading@10: s->dts_ref_dts_delta = INT_MIN; yading@10: s->pts_dts_delta = INT_MIN; yading@10: return s; yading@10: yading@10: err_out: yading@10: if (s) yading@10: av_freep(&s->priv_data); yading@10: av_free(s); yading@10: return NULL; yading@10: } yading@10: yading@10: void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove){ yading@10: int i; yading@10: yading@10: s->dts= s->pts= AV_NOPTS_VALUE; yading@10: s->pos= -1; yading@10: s->offset= 0; yading@10: for(i = 0; i < AV_PARSER_PTS_NB; i++) { yading@10: if ( s->cur_offset + off >= s->cur_frame_offset[i] yading@10: && (s->frame_offset < s->cur_frame_offset[i] || yading@10: (!s->frame_offset && !s->next_frame_offset)) // first field/frame yading@10: // check disabled since MPEG-TS does not send complete PES packets yading@10: && /*s->next_frame_offset + off <*/ s->cur_frame_end[i]){ yading@10: s->dts= s->cur_frame_dts[i]; yading@10: s->pts= s->cur_frame_pts[i]; yading@10: s->pos= s->cur_frame_pos[i]; yading@10: s->offset = s->next_frame_offset - s->cur_frame_offset[i]; yading@10: if(remove) yading@10: s->cur_frame_offset[i]= INT64_MAX; yading@10: if(s->cur_offset + off < s->cur_frame_end[i]) yading@10: break; yading@10: } yading@10: } yading@10: } yading@10: yading@10: int av_parser_parse2(AVCodecParserContext *s, yading@10: AVCodecContext *avctx, yading@10: uint8_t **poutbuf, int *poutbuf_size, yading@10: const uint8_t *buf, int buf_size, yading@10: int64_t pts, int64_t dts, yading@10: int64_t pos) yading@10: { yading@10: int index, i; yading@10: uint8_t dummy_buf[FF_INPUT_BUFFER_PADDING_SIZE]; yading@10: yading@10: if(!(s->flags & PARSER_FLAG_FETCHED_OFFSET)) { yading@10: s->next_frame_offset = yading@10: s->cur_offset = pos; yading@10: s->flags |= PARSER_FLAG_FETCHED_OFFSET; yading@10: } yading@10: yading@10: if (buf_size == 0) { yading@10: /* padding is always necessary even if EOF, so we add it here */ yading@10: memset(dummy_buf, 0, sizeof(dummy_buf)); yading@10: buf = dummy_buf; yading@10: } else if (s->cur_offset + buf_size != yading@10: s->cur_frame_end[s->cur_frame_start_index]) { /* skip remainder packets */ yading@10: /* add a new packet descriptor */ yading@10: i = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1); yading@10: s->cur_frame_start_index = i; yading@10: s->cur_frame_offset[i] = s->cur_offset; yading@10: s->cur_frame_end[i] = s->cur_offset + buf_size; yading@10: s->cur_frame_pts[i] = pts; yading@10: s->cur_frame_dts[i] = dts; yading@10: s->cur_frame_pos[i] = pos; yading@10: } yading@10: yading@10: if (s->fetch_timestamp){ yading@10: s->fetch_timestamp=0; yading@10: s->last_pts = s->pts; yading@10: s->last_dts = s->dts; yading@10: s->last_pos = s->pos; yading@10: ff_fetch_timestamp(s, 0, 0); yading@10: } yading@10: yading@10: /* WARNING: the returned index can be negative */ yading@10: index = s->parser->parser_parse(s, avctx, (const uint8_t **)poutbuf, poutbuf_size, buf, buf_size); yading@10: /* update the file pointer */ yading@10: if (*poutbuf_size) { yading@10: /* fill the data for the current frame */ yading@10: s->frame_offset = s->next_frame_offset; yading@10: yading@10: /* offset of the next frame */ yading@10: s->next_frame_offset = s->cur_offset + index; yading@10: s->fetch_timestamp=1; yading@10: } yading@10: if (index < 0) yading@10: index = 0; yading@10: s->cur_offset += index; yading@10: return index; yading@10: } yading@10: yading@10: int av_parser_change(AVCodecParserContext *s, yading@10: AVCodecContext *avctx, yading@10: uint8_t **poutbuf, int *poutbuf_size, yading@10: const uint8_t *buf, int buf_size, int keyframe){ yading@10: yading@10: if(s && s->parser->split){ yading@10: if((avctx->flags & CODEC_FLAG_GLOBAL_HEADER) || (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)){ yading@10: int i= s->parser->split(avctx, buf, buf_size); yading@10: buf += i; yading@10: buf_size -= i; yading@10: } yading@10: } yading@10: yading@10: /* cast to avoid warning about discarding qualifiers */ yading@10: *poutbuf= (uint8_t *) buf; yading@10: *poutbuf_size= buf_size; yading@10: if(avctx->extradata){ yading@10: if( (keyframe && (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)) yading@10: /*||(s->pict_type != AV_PICTURE_TYPE_I && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_NOKEY))*/ yading@10: /*||(? && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_BEGIN)*/){ yading@10: int size= buf_size + avctx->extradata_size; yading@10: *poutbuf_size= size; yading@10: *poutbuf= av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: yading@10: memcpy(*poutbuf, avctx->extradata, avctx->extradata_size); yading@10: memcpy((*poutbuf) + avctx->extradata_size, buf, buf_size + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: return 1; yading@10: } yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: void av_parser_close(AVCodecParserContext *s) yading@10: { yading@10: if(s){ yading@10: if (s->parser->parser_close) yading@10: s->parser->parser_close(s); yading@10: av_free(s->priv_data); yading@10: av_free(s); yading@10: } yading@10: } yading@10: yading@10: /*****************************************************/ yading@10: yading@10: int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_size) yading@10: { yading@10: if(pc->overread){ yading@10: av_dlog(NULL, "overread %d, state:%X next:%d index:%d o_index:%d\n", yading@10: pc->overread, pc->state, next, pc->index, pc->overread_index); yading@10: av_dlog(NULL, "%X %X %X %X\n", (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); yading@10: } yading@10: yading@10: /* Copy overread bytes from last frame into buffer. */ yading@10: for(; pc->overread>0; pc->overread--){ yading@10: pc->buffer[pc->index++]= pc->buffer[pc->overread_index++]; yading@10: } yading@10: yading@10: /* flush remaining if EOF */ yading@10: if(!*buf_size && next == END_NOT_FOUND){ yading@10: next= 0; yading@10: } yading@10: yading@10: pc->last_index= pc->index; yading@10: yading@10: /* copy into buffer end return */ yading@10: if(next == END_NOT_FOUND){ yading@10: void* new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, (*buf_size) + pc->index + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: yading@10: if(!new_buffer) yading@10: return AVERROR(ENOMEM); yading@10: pc->buffer = new_buffer; yading@10: memcpy(&pc->buffer[pc->index], *buf, *buf_size); yading@10: pc->index += *buf_size; yading@10: return -1; yading@10: } yading@10: yading@10: *buf_size= yading@10: pc->overread_index= pc->index + next; yading@10: yading@10: /* append to buffer */ yading@10: if(pc->index){ yading@10: void* new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, next + pc->index + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: yading@10: if(!new_buffer) yading@10: return AVERROR(ENOMEM); yading@10: pc->buffer = new_buffer; yading@10: if (next > -FF_INPUT_BUFFER_PADDING_SIZE) yading@10: memcpy(&pc->buffer[pc->index], *buf, yading@10: next + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: pc->index = 0; yading@10: *buf= pc->buffer; yading@10: } yading@10: yading@10: /* store overread bytes */ yading@10: for(;next < 0; next++){ yading@10: pc->state = (pc->state<<8) | pc->buffer[pc->last_index + next]; yading@10: pc->state64 = (pc->state64<<8) | pc->buffer[pc->last_index + next]; yading@10: pc->overread++; yading@10: } yading@10: yading@10: if(pc->overread){ yading@10: av_dlog(NULL, "overread %d, state:%X next:%d index:%d o_index:%d\n", yading@10: pc->overread, pc->state, next, pc->index, pc->overread_index); yading@10: av_dlog(NULL, "%X %X %X %X\n", (*buf)[0], (*buf)[1],(*buf)[2],(*buf)[3]); yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: void ff_parse_close(AVCodecParserContext *s) yading@10: { yading@10: ParseContext *pc = s->priv_data; yading@10: yading@10: av_freep(&pc->buffer); yading@10: } yading@10: yading@10: /*************************/ yading@10: yading@10: int ff_mpeg4video_split(AVCodecContext *avctx, yading@10: const uint8_t *buf, int buf_size) yading@10: { yading@10: int i; yading@10: uint32_t state= -1; yading@10: yading@10: for(i=0; i