nengel@2: /* nengel@2: * H.26L/H.264/AVC/JVT/14496-10/... parser nengel@2: * Copyright (c) 2003 Michael Niedermayer nengel@2: * nengel@2: * This file is part of FFmpeg. nengel@2: * nengel@2: * FFmpeg is free software; you can redistribute it and/or nengel@2: * modify it under the terms of the GNU Lesser General Public nengel@2: * License as published by the Free Software Foundation; either nengel@2: * version 2.1 of the License, or (at your option) any later version. nengel@2: * nengel@2: * FFmpeg is distributed in the hope that it will be useful, nengel@2: * but WITHOUT ANY WARRANTY; without even the implied warranty of nengel@2: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nengel@2: * Lesser General Public License for more details. nengel@2: * nengel@2: * You should have received a copy of the GNU Lesser General Public nengel@2: * License along with FFmpeg; if not, write to the Free Software nengel@2: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA nengel@2: */ nengel@2: nengel@2: /** nengel@2: * @file nengel@2: * H.264 / AVC / MPEG4 part10 parser. nengel@2: * @author Michael Niedermayer nengel@2: */ nengel@2: nengel@2: #include nengel@2: nengel@2: #include "golomb.h" nengel@2: #include "libavutil/error.h" nengel@2: #include "h264_types.h" nengel@2: nengel@2: #undef NDEBUG nengel@2: #include nengel@2: nengel@2: #define END_NOT_FOUND (-100) nengel@2: nengel@2: static int ff_h264_find_frame_end(ParserContext *s, const uint8_t *buf, int buf_size) nengel@2: { nengel@2: int i; nengel@2: uint32_t state; nengel@2: nengel@2: state= s->state; nengel@2: if(state>13) nengel@2: state= 7; nengel@2: nengel@2: for(i=0; i7, 1->4, 0->5 nengel@2: else if(buf[i]) state = 7; nengel@2: else state>>=1; //2->1, 1->0, 0->0 nengel@2: }else if(state<=5){ nengel@2: int v= buf[i] & 0x1F; nengel@2: if(v==6 || v==7 || v==8 || v==9){ nengel@2: if(s->frame_start_found){ nengel@2: i++; nengel@2: goto found; nengel@2: } nengel@2: }else if(v==1 || v==2 || v==5){ nengel@2: if(s->frame_start_found){ nengel@2: state+=8; nengel@2: continue; nengel@2: }else nengel@2: s->frame_start_found = 1; nengel@2: } nengel@2: state= 7; nengel@2: }else{ nengel@2: if(buf[i] & 0x80) nengel@2: goto found; nengel@2: state= 7; nengel@2: } nengel@2: } nengel@2: s->state= state; nengel@2: return END_NOT_FOUND; nengel@2: nengel@2: found: nengel@2: s->state=7; nengel@2: s->frame_start_found= 0; nengel@2: return i-(state&5); nengel@2: } nengel@2: nengel@2: static int ff_combine_frame(ParserContext *s, GetBitContext *gb, int next, uint8_t **buf, int *buf_size) nengel@2: { nengel@2: int i; nengel@2: /* Copy overread bytes from last frame into buffer. */ nengel@2: for(i =0; s->overread_cnt>0; s->overread_cnt--, i++){ nengel@2: gb->raw[s->index++]= s->overread[i]; nengel@2: } nengel@2: nengel@2: /* EOF - END_NOT_FOUND means no next frame start is found in current partial read. If buf_size of the partial read is 0 we are at EOF */ nengel@2: if(!*buf_size && next == END_NOT_FOUND){ nengel@2: next= 0; nengel@2: } nengel@2: s->last_index= s->index; nengel@2: nengel@2: /* copy into buffer end return */ nengel@2: if(next == END_NOT_FOUND){ nengel@2: gb->raw = av_fast_realloc(gb->raw, &gb->alloc_size, (*buf_size) + s->index + FF_INPUT_BUFFER_PADDING_SIZE); nengel@2: memcpy(&gb->raw[s->index], *buf, *buf_size); nengel@2: s->index += *buf_size; nengel@2: return -1; nengel@2: } nengel@2: nengel@2: ///end found nengel@2: *buf_size= s->index + next; nengel@2: /* append to buffer */ nengel@2: nengel@2: gb->raw = av_fast_realloc(gb->raw, &gb->alloc_size, next + s->index + FF_INPUT_BUFFER_PADDING_SIZE); nengel@2: memcpy(&gb->raw[s->index], *buf, next + FF_INPUT_BUFFER_PADDING_SIZE ); nengel@2: s->index = 0; nengel@2: nengel@2: /* store overread bytes */ nengel@2: for(i=0; next < 0; next++, i++){ nengel@2: s->state = (s->state<<8) | gb->raw[s->last_index + next]; nengel@2: s->overread[i] = gb->raw[s->last_index + next]; nengel@2: s->overread_cnt++; nengel@2: } nengel@2: nengel@2: return 0; nengel@2: } nengel@2: nengel@2: static int h264_parse(ParserContext *s, GetBitContext *gb, nengel@2: uint8_t *buf, int buf_size) nengel@2: { nengel@2: int next; nengel@2: nengel@2: next= ff_h264_find_frame_end(s, buf, buf_size); nengel@2: nengel@2: if (ff_combine_frame(s, gb, next, &buf, &buf_size) < 0) { nengel@2: gb->buf_size = 0; nengel@2: return buf_size; nengel@2: } nengel@2: nengel@2: if(next<0 && next != END_NOT_FOUND){ nengel@2: assert(s->last_index + next >= 0 ); nengel@2: ff_h264_find_frame_end(s, &gb->raw[s->last_index + next], -next); //update state nengel@2: } nengel@2: nengel@2: gb->buf_size = buf_size; nengel@2: return next; nengel@2: } nengel@2: nengel@2: static int ff_raw_read_partial_packet(ParserContext *pc) nengel@2: { nengel@2: int len= -1; nengel@2: nengel@2: if (!pc->eof_reached){ nengel@2: len = read( pc->ifile, pc->data, pc->buffer_size); nengel@2: // printf("read task %d\t%d\n", pc->ifile, len); fflush(NULL); nengel@2: if (len < pc->buffer_size) { nengel@2: pc->eof_reached = 1; nengel@2: } nengel@2: } nengel@2: nengel@2: return len; nengel@2: } nengel@2: nengel@2: void av_read_frame_internal(ParserContext *pc, GetBitContext *gb){ nengel@2: int len; nengel@2: uint8_t dummy_buf[FF_INPUT_BUFFER_PADDING_SIZE]={0}; nengel@2: av_fast_malloc(&gb->raw, &gb->alloc_size, 2048+FF_INPUT_BUFFER_PADDING_SIZE); nengel@2: nengel@2: //Parsing is performed before read, since there are ussually leftovers from parsing the previous frame. nengel@2: for(;;) { nengel@2: if (pc->cur_len>0){ nengel@2: len = h264_parse(pc, gb, pc->cur_ptr, pc->cur_len); nengel@2: if (len<0) nengel@2: len =0; nengel@2: //* increment read pointer */ nengel@2: pc->cur_ptr += len; nengel@2: pc->cur_len -= len; nengel@2: nengel@2: if (gb->buf_size) { nengel@2: break; nengel@2: } nengel@2: } nengel@2: nengel@2: //check for ret and not parser->eof_reached as one "read" can contain more than 1 frame nengel@2: pc->size= ff_raw_read_partial_packet(pc); nengel@2: if (pc->size < 0) { nengel@2: pc->final_frame =1; nengel@2: /* return the last frames, if any */ nengel@2: h264_parse(pc, gb, dummy_buf, 0); nengel@2: break; nengel@2: } nengel@2: pc->cur_ptr = pc->data; nengel@2: pc->cur_len = pc->size; nengel@2: } nengel@2: nengel@2: assert(gb->raw!=NULL); nengel@2: nengel@2: } nengel@2: nengel@2: ParserContext *get_parse_context(int ifile){ nengel@2: ParserContext *pc = av_mallocz(sizeof(ParserContext)); nengel@2: pc->buffer_size = 2048; nengel@2: pc->final_frame = 0; nengel@2: pc->cur_len= 0; nengel@2: pc->data = av_mallocz(2048 + FF_INPUT_BUFFER_PADDING_SIZE); nengel@2: pc->size = 2048; nengel@2: pc->eof_reached =0; nengel@2: pc->ifile = ifile; nengel@2: nengel@2: return pc; nengel@2: } nengel@2: nengel@2: void free_parse_context(ParserContext *pc){ nengel@2: av_free(pc->data); nengel@2: av_free(pc); nengel@2: }