avcodec/dnxhd_parser: Fix parser when input does not have nicely sized packets
[ffmpeg.git] / libavcodec / dnxhd_parser.c
1 /*
2  * DNxHD/VC-3 parser
3  * Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
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  * DNxHD/VC-3 parser
25  */
26
27 #include "parser.h"
28 #include "dnxhddata.h"
29
30 typedef struct {
31     ParseContext pc;
32     int cur_byte;
33     int remaining;
34     int w, h;
35 } DNXHDParserContext;
36
37 static int dnxhd_find_frame_end(DNXHDParserContext *dctx,
38                                 const uint8_t *buf, int buf_size)
39 {
40     ParseContext *pc = &dctx->pc;
41     uint64_t state = pc->state64;
42     int pic_found = pc->frame_start_found;
43     int i = 0;
44
45     if (!pic_found) {
46         for (i = 0; i < buf_size; i++) {
47             state = (state << 8) | buf[i];
48             if (ff_dnxhd_check_header_prefix(state & 0xffffffffff00LL) != 0) {
49                 i++;
50                 pic_found = 1;
51                 dctx->cur_byte = 0;
52                 dctx->remaining = 0;
53                 break;
54             }
55         }
56     }
57
58     if (pic_found && !dctx->remaining) {
59         if (!buf_size) /* EOF considered as end of frame */
60             return 0;
61         for (; i < buf_size; i++) {
62             dctx->cur_byte++;
63             state = (state << 8) | buf[i];
64
65             if (dctx->cur_byte == 24) {
66                 dctx->h = (state >> 32) & 0xFFFF;
67             } else if (dctx->cur_byte == 26) {
68                 dctx->w = (state >> 32) & 0xFFFF;
69             } else if (dctx->cur_byte == 42) {
70                 int cid = (state >> 32) & 0xFFFFFFFF;
71                 int remaining;
72
73                 if (cid <= 0)
74                     continue;
75
76                 remaining = avpriv_dnxhd_get_frame_size(cid);
77                 if (remaining <= 0) {
78                     remaining = avpriv_dnxhd_get_hr_frame_size(cid, dctx->w, dctx->h);
79                     if (remaining <= 0)
80                         continue;
81                 }
82                 remaining += i - 47;
83                 dctx->remaining = remaining;
84                 if (buf_size >= dctx->remaining) {
85                     pc->frame_start_found = 0;
86                     pc->state64 = -1;
87                     dctx->cur_byte = 0;
88                     dctx->remaining = 0;
89                     return remaining;
90                 } else {
91                     dctx->remaining -= buf_size;
92                     // Update variables for correctness, they are currently not used beyond here
93                     state = -1;
94                     dctx->cur_byte += buf_size - i;
95                     break;
96                 }
97             }
98         }
99     } else if (pic_found) {
100         if (dctx->remaining > buf_size) {
101             dctx->remaining -= buf_size;
102         } else {
103             int remaining = dctx->remaining;
104
105             pc->frame_start_found = 0;
106             pc->state64 = -1;
107             dctx->cur_byte = 0;
108             dctx->remaining = 0;
109             return remaining;
110         }
111     }
112     pc->frame_start_found = pic_found;
113     pc->state64 = state;
114     return END_NOT_FOUND;
115 }
116
117 static int dnxhd_parse(AVCodecParserContext *s,
118                        AVCodecContext *avctx,
119                        const uint8_t **poutbuf, int *poutbuf_size,
120                        const uint8_t *buf, int buf_size)
121 {
122     DNXHDParserContext *dctx = s->priv_data;
123     ParseContext *pc = &dctx->pc;
124     int next;
125
126     if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
127         next = buf_size;
128     } else {
129         next = dnxhd_find_frame_end(dctx, buf, buf_size);
130         if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
131             *poutbuf      = NULL;
132             *poutbuf_size = 0;
133             return buf_size;
134         }
135     }
136     *poutbuf      = buf;
137     *poutbuf_size = buf_size;
138     return next;
139 }
140
141 AVCodecParser ff_dnxhd_parser = {
142     .codec_ids      = { AV_CODEC_ID_DNXHD },
143     .priv_data_size = sizeof(DNXHDParserContext),
144     .parser_parse   = dnxhd_parse,
145     .parser_close   = ff_parse_close,
146 };