blob: a1f632a620ec3f116504e8f7702b793ea2190cd2
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_get_hr_frame_size(int cid, int w, int h) |
38 | { |
39 | int result, i = ff_dnxhd_get_cid_table(cid); |
40 | |
41 | if (i < 0) |
42 | return i; |
43 | |
44 | result = ((h + 15) / 16) * ((w + 15) / 16) * ff_dnxhd_cid_table[i].packet_scale.num / ff_dnxhd_cid_table[i].packet_scale.den; |
45 | result = (result + 2048) / 4096 * 4096; |
46 | |
47 | return FFMAX(result, 8192); |
48 | } |
49 | |
50 | static int dnxhd_find_frame_end(DNXHDParserContext *dctx, |
51 | const uint8_t *buf, int buf_size) |
52 | { |
53 | ParseContext *pc = &dctx->pc; |
54 | uint64_t state = pc->state64; |
55 | int pic_found = pc->frame_start_found; |
56 | int i = 0; |
57 | |
58 | if (!pic_found) { |
59 | for (i = 0; i < buf_size; i++) { |
60 | state = (state << 8) | buf[i]; |
61 | if (ff_dnxhd_check_header_prefix(state & 0xffffffffff00LL) != 0) { |
62 | i++; |
63 | pic_found = 1; |
64 | dctx->cur_byte = 0; |
65 | dctx->remaining = 0; |
66 | break; |
67 | } |
68 | } |
69 | } |
70 | |
71 | if (pic_found && !dctx->remaining) { |
72 | if (!buf_size) /* EOF considered as end of frame */ |
73 | return 0; |
74 | for (; i < buf_size; i++) { |
75 | dctx->cur_byte++; |
76 | state = (state << 8) | buf[i]; |
77 | |
78 | if (dctx->cur_byte == 24) { |
79 | dctx->h = (state >> 32) & 0xFFFF; |
80 | } else if (dctx->cur_byte == 26) { |
81 | dctx->w = (state >> 32) & 0xFFFF; |
82 | } else if (dctx->cur_byte == 42) { |
83 | int cid = (state >> 32) & 0xFFFFFFFF; |
84 | |
85 | if (cid <= 0) |
86 | continue; |
87 | |
88 | dctx->remaining = avpriv_dnxhd_get_frame_size(cid); |
89 | if (dctx->remaining <= 0) { |
90 | dctx->remaining = dnxhd_get_hr_frame_size(cid, dctx->w, dctx->h); |
91 | if (dctx->remaining <= 0) |
92 | return dctx->remaining; |
93 | } |
94 | if (buf_size - i + 47 >= dctx->remaining) { |
95 | int remaining = dctx->remaining; |
96 | |
97 | pc->frame_start_found = 0; |
98 | pc->state64 = -1; |
99 | dctx->cur_byte = 0; |
100 | dctx->remaining = 0; |
101 | return remaining; |
102 | } else { |
103 | dctx->remaining -= buf_size; |
104 | } |
105 | } |
106 | } |
107 | } else if (pic_found) { |
108 | if (dctx->remaining > buf_size) { |
109 | dctx->remaining -= buf_size; |
110 | } else { |
111 | int remaining = dctx->remaining; |
112 | |
113 | pc->frame_start_found = 0; |
114 | pc->state64 = -1; |
115 | dctx->cur_byte = 0; |
116 | dctx->remaining = 0; |
117 | return remaining; |
118 | } |
119 | } |
120 | pc->frame_start_found = pic_found; |
121 | pc->state64 = state; |
122 | return END_NOT_FOUND; |
123 | } |
124 | |
125 | static int dnxhd_parse(AVCodecParserContext *s, |
126 | AVCodecContext *avctx, |
127 | const uint8_t **poutbuf, int *poutbuf_size, |
128 | const uint8_t *buf, int buf_size) |
129 | { |
130 | DNXHDParserContext *dctx = s->priv_data; |
131 | ParseContext *pc = &dctx->pc; |
132 | int next; |
133 | |
134 | if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { |
135 | next = buf_size; |
136 | } else { |
137 | next = dnxhd_find_frame_end(dctx, buf, buf_size); |
138 | if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { |
139 | *poutbuf = NULL; |
140 | *poutbuf_size = 0; |
141 | return buf_size; |
142 | } |
143 | } |
144 | *poutbuf = buf; |
145 | *poutbuf_size = buf_size; |
146 | return next; |
147 | } |
148 | |
149 | AVCodecParser ff_dnxhd_parser = { |
150 | .codec_ids = { AV_CODEC_ID_DNXHD }, |
151 | .priv_data_size = sizeof(DNXHDParserContext), |
152 | .parser_parse = dnxhd_parse, |
153 | .parser_close = ff_parse_close, |
154 | }; |
155 |