1/* 2 * MJPEG parser 3 * Copyright (c) 2000, 2001 Fabrice Bellard 4 * Copyright (c) 2003 Alex Beregszaszi 5 * Copyright (c) 2003-2004 Michael Niedermayer 6 * 7 * This file is part of FFmpeg. 8 * 9 * FFmpeg is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * FFmpeg is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with FFmpeg; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24/** 25 * @file 26 * MJPEG parser. 27 */ 28 29#include "parser.h" 30 31typedef struct MJPEGParserContext{ 32 ParseContext pc; 33 int size; 34}MJPEGParserContext; 35 36/** 37 * Find the end of the current frame in the bitstream. 38 * @return the position of the first byte of the next frame, or -1 39 */ 40static int find_frame_end(MJPEGParserContext *m, const uint8_t *buf, int buf_size){ 41 ParseContext *pc= &m->pc; 42 int vop_found, i; 43 uint32_t state; 44 45 vop_found= pc->frame_start_found; 46 state= pc->state; 47 48 i=0; 49 if(!vop_found){ 50 for(i=0; i<buf_size;){ 51 state= (state<<8) | buf[i]; 52 if(state>=0xFFC00000 && state<=0xFFFEFFFF){ 53 if(state>=0xFFD80000 && state<=0xFFD8FFFF){ 54 i++; 55 vop_found=1; 56 break; 57 }else if(state<0xFFD00000 || state>0xFFD9FFFF){ 58 m->size= (state&0xFFFF)-1; 59 } 60 } 61 if(m->size>0){ 62 int size= FFMIN(buf_size-i, m->size); 63 i+=size; 64 m->size-=size; 65 state=0; 66 continue; 67 }else 68 i++; 69 } 70 } 71 72 if(vop_found){ 73 /* EOF considered as end of frame */ 74 if (buf_size == 0) 75 return 0; 76 for(; i<buf_size;){ 77 state= (state<<8) | buf[i]; 78 if(state>=0xFFC00000 && state<=0xFFFEFFFF){ 79 if(state>=0xFFD80000 && state<=0xFFD8FFFF){ 80 pc->frame_start_found=0; 81 pc->state=0; 82 return i-3; 83 } else if(state<0xFFD00000 || state>0xFFD9FFFF){ 84 m->size= (state&0xFFFF)-1; 85 } 86 } 87 if(m->size>0){ 88 int size= FFMIN(buf_size-i, m->size); 89 i+=size; 90 m->size-=size; 91 state=0; 92 continue; 93 }else 94 i++; 95 } 96 } 97 pc->frame_start_found= vop_found; 98 pc->state= state; 99 return END_NOT_FOUND; 100} 101 102static int jpeg_parse(AVCodecParserContext *s, 103 AVCodecContext *avctx, 104 const uint8_t **poutbuf, int *poutbuf_size, 105 const uint8_t *buf, int buf_size) 106{ 107 MJPEGParserContext *m = s->priv_data; 108 ParseContext *pc = &m->pc; 109 int next; 110 111 if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){ 112 next= buf_size; 113 }else{ 114 next= find_frame_end(m, buf, buf_size); 115 116 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { 117 *poutbuf = NULL; 118 *poutbuf_size = 0; 119 return buf_size; 120 } 121 } 122 123 *poutbuf = buf; 124 *poutbuf_size = buf_size; 125 return next; 126} 127 128 129AVCodecParser ff_mjpeg_parser = { 130 .codec_ids = { AV_CODEC_ID_MJPEG }, 131 .priv_data_size = sizeof(MJPEGParserContext), 132 .parser_parse = jpeg_parse, 133 .parser_close = ff_parse_close, 134}; 135