/src/ffmpeg/libavcodec/apv_parser.c
Line | Count | Source |
1 | | /* |
2 | | * This file is part of FFmpeg. |
3 | | * |
4 | | * FFmpeg is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * FFmpeg is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | | * Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General Public |
15 | | * License along with FFmpeg; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | | */ |
18 | | |
19 | | #include "libavutil/avassert.h" |
20 | | #include "libavutil/buffer.h" |
21 | | #include "libavutil/mem.h" |
22 | | |
23 | | #include "avcodec.h" |
24 | | #include "apv.h" |
25 | | #include "cbs.h" |
26 | | #include "cbs_apv.h" |
27 | | #include "parser.h" |
28 | | #include "parser_internal.h" |
29 | | |
30 | | typedef struct APVParseContext { |
31 | | ParseContext pc; |
32 | | |
33 | | CodedBitstreamContext *cbc; |
34 | | CodedBitstreamFragment au; |
35 | | } APVParseContext; |
36 | | |
37 | | static const enum AVPixelFormat apv_format_table[5][5] = { |
38 | | { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 }, |
39 | | { 0 }, // 4:2:0 is not valid. |
40 | | { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV422P16 }, |
41 | | { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P16 }, |
42 | | { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUVA444P16 }, |
43 | | }; |
44 | | |
45 | | static int find_frame_end(APVParseContext *p, const uint8_t *buf, int buf_size) |
46 | 132k | { |
47 | 132k | ParseContext *pc = &p->pc; |
48 | 132k | int pic_found, i = 0; |
49 | 132k | uint32_t state; |
50 | | |
51 | 132k | pic_found = pc->frame_start_found; |
52 | 132k | state = pc->state; |
53 | | |
54 | 132k | if (buf_size == 0) { |
55 | 0 | pc->frame_start_found = 0; |
56 | 0 | pc->state = -1; |
57 | 0 | return 0; |
58 | 0 | } |
59 | | |
60 | 132k | if (!pic_found) { |
61 | 8.40M | for (; i < buf_size; i++) { |
62 | 8.35M | state = (state << 8) | buf[i]; |
63 | 8.35M | if (state == APV_SIGNATURE) { |
64 | 44.2k | i++; |
65 | 44.2k | pic_found = 1; |
66 | 44.2k | break; |
67 | 44.2k | } |
68 | 8.35M | } |
69 | 86.1k | } |
70 | | |
71 | 132k | if (pic_found) { |
72 | 15.5M | for(; i < buf_size; i++) { |
73 | 15.5M | state = (state << 8) | buf[i]; |
74 | 15.5M | if (state == APV_SIGNATURE) { |
75 | 43.7k | pc->frame_start_found = 0; |
76 | 43.7k | pc->state = -1; |
77 | 43.7k | return i - 3; |
78 | 43.7k | } |
79 | 15.5M | } |
80 | 90.1k | } |
81 | | |
82 | 88.3k | pc->frame_start_found = pic_found; |
83 | 88.3k | pc->state = state; |
84 | 88.3k | return END_NOT_FOUND; |
85 | 132k | } |
86 | | |
87 | | static void dummy_free(void *opaque, uint8_t *data) |
88 | 151k | { |
89 | 151k | av_assert0(opaque == data); |
90 | 151k | } |
91 | | |
92 | | static int parse(AVCodecParserContext *s, |
93 | | AVCodecContext *avctx, |
94 | | const uint8_t **poutbuf, int *poutbuf_size, |
95 | | const uint8_t *buf, int buf_size) |
96 | 241k | { |
97 | 241k | APVParseContext *p = s->priv_data; |
98 | 241k | CodedBitstreamFragment *au = &p->au; |
99 | 241k | AVBufferRef *ref = NULL; |
100 | 241k | int next, ret; |
101 | | |
102 | 241k | if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { |
103 | 109k | next = buf_size; |
104 | 132k | } else { |
105 | 132k | next = find_frame_end(p, buf, buf_size); |
106 | | |
107 | 132k | if (ff_combine_frame(&p->pc, next, &buf, &buf_size) < 0) { |
108 | 88.3k | *poutbuf = NULL; |
109 | 88.3k | *poutbuf_size = 0; |
110 | 88.3k | return buf_size; |
111 | 88.3k | } |
112 | 132k | } |
113 | | |
114 | 153k | *poutbuf = buf; |
115 | 153k | *poutbuf_size = buf_size; |
116 | | |
117 | 153k | if (!buf_size) |
118 | 2.04k | return 0; |
119 | | |
120 | 151k | ref = av_buffer_create((uint8_t *)buf, buf_size, dummy_free, |
121 | 151k | (void *)buf, AV_BUFFER_FLAG_READONLY); |
122 | 151k | if (!ref) |
123 | 0 | return next; |
124 | | |
125 | 151k | p->cbc->log_ctx = avctx; |
126 | | |
127 | 151k | ret = ff_cbs_read(p->cbc, au, ref, buf, buf_size); |
128 | 151k | if (ret < 0) { |
129 | 126k | av_log(avctx, AV_LOG_ERROR, "Failed to parse access unit.\n"); |
130 | 126k | goto end; |
131 | 126k | } |
132 | | |
133 | 25.5k | s->key_frame = 1; |
134 | 25.5k | s->pict_type = AV_PICTURE_TYPE_I; |
135 | 25.5k | s->field_order = AV_FIELD_UNKNOWN; |
136 | 25.5k | s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; |
137 | | |
138 | 32.6k | for (int i = 0; i < au->nb_units; i++) { |
139 | 19.9k | const CodedBitstreamUnit *pbu = &au->units[i]; |
140 | | |
141 | 19.9k | switch (pbu->type) { |
142 | 13.4k | case APV_PBU_PRIMARY_FRAME: { |
143 | 13.4k | const APVRawFrame *frame = pbu->content; |
144 | 13.4k | const APVRawFrameHeader *header = &frame->frame_header; |
145 | 13.4k | const APVRawFrameInfo *info = &header->frame_info; |
146 | 13.4k | int bit_depth = info->bit_depth_minus8 + 8; |
147 | | |
148 | 13.4k | if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2) |
149 | 628 | break; |
150 | | |
151 | 12.8k | s->width = info->frame_width; |
152 | 12.8k | s->height = info->frame_height; |
153 | 12.8k | s->format = apv_format_table[info->chroma_format_idc][bit_depth - 4 >> 2]; |
154 | 12.8k | avctx->profile = info->profile_idc; |
155 | 12.8k | avctx->level = info->level_idc; |
156 | 12.8k | avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; |
157 | 12.8k | avctx->color_primaries = header->color_primaries; |
158 | 12.8k | avctx->color_trc = header->transfer_characteristics; |
159 | 12.8k | avctx->colorspace = header->matrix_coefficients; |
160 | 12.8k | avctx->color_range = header->full_range_flag ? AVCOL_RANGE_JPEG |
161 | 12.8k | : AVCOL_RANGE_MPEG; |
162 | 12.8k | goto end; |
163 | 13.4k | } |
164 | 6.50k | default: |
165 | 6.50k | break; |
166 | 19.9k | } |
167 | 19.9k | } |
168 | | |
169 | 151k | end: |
170 | 151k | ff_cbs_fragment_reset(au); |
171 | 151k | av_assert1(av_buffer_get_ref_count(ref) == 1); |
172 | 151k | av_buffer_unref(&ref); |
173 | 151k | p->cbc->log_ctx = NULL; |
174 | | |
175 | 151k | return next; |
176 | 25.5k | } |
177 | | |
178 | | static const CodedBitstreamUnitType decompose_unit_types[] = { |
179 | | APV_PBU_PRIMARY_FRAME, |
180 | | }; |
181 | | |
182 | | static av_cold int init(AVCodecParserContext *s) |
183 | 2.66k | { |
184 | 2.66k | APVParseContext *p = s->priv_data; |
185 | 2.66k | int ret; |
186 | | |
187 | 2.66k | ret = ff_cbs_init(&p->cbc, AV_CODEC_ID_APV, NULL); |
188 | 2.66k | if (ret < 0) |
189 | 0 | return ret; |
190 | | |
191 | 2.66k | p->cbc->decompose_unit_types = decompose_unit_types; |
192 | 2.66k | p->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); |
193 | | |
194 | 2.66k | return 0; |
195 | 2.66k | } |
196 | | |
197 | | static av_cold void close(AVCodecParserContext *s) |
198 | 2.66k | { |
199 | 2.66k | APVParseContext *p = s->priv_data; |
200 | 2.66k | ParseContext *pc = &p->pc; |
201 | | |
202 | 2.66k | av_freep(&pc->buffer); |
203 | 2.66k | ff_cbs_fragment_free(&p->au); |
204 | 2.66k | ff_cbs_close(&p->cbc); |
205 | 2.66k | } |
206 | | |
207 | | const FFCodecParser ff_apv_parser = { |
208 | | PARSER_CODEC_LIST(AV_CODEC_ID_APV), |
209 | | .priv_data_size = sizeof(APVParseContext), |
210 | | .init = init, |
211 | | .parse = parse, |
212 | | .close = close, |
213 | | }; |