p7zip: assorted fixes
[oi-userland.git] / components / encumbered / gst-plugins-bad / patches / 0030-really-fix-h264-parsing.patch
blob486678946545e69cfdef737051d398a8f2ec23cb
1 # Description: Fixes failure to decode many common video files encoded as AVC 1 Baseline - L2.1, Baseline - L1.1 & others
2 # Forwarded: not-needed
3 # Origin: upstream
4 # Bug-Ubuntu: https://bugs.launchpad.net/bugs/973014
5 --- gst-plugins-bad0.10-0.10.23.orig/gst/videoparsers/gsth264parse.c
6 +++ gst-plugins-bad0.10-0.10.23/gst/videoparsers/gsth264parse.c
7 @@ -177,11 +177,7 @@ gst_h264_parse_reset_frame (GstH264Parse
8 GST_DEBUG_OBJECT (h264parse, "reset frame");
10 /* done parsing; reset state */
11 - h264parse->nalu.valid = FALSE;
12 - h264parse->nalu.offset = 0;
13 - h264parse->nalu.sc_offset = 0;
14 - h264parse->nalu.size = 0;
15 - h264parse->current_off = 0;
16 + h264parse->current_off = -1;
18 h264parse->picture_start = FALSE;
19 h264parse->update_caps = FALSE;
20 @@ -213,6 +209,8 @@ gst_h264_parse_reset (GstH264Parse * h26
22 h264parse->last_report = GST_CLOCK_TIME_NONE;
23 h264parse->push_codec = FALSE;
24 + h264parse->have_pps = FALSE;
25 + h264parse->have_sps = FALSE;
27 h264parse->dts = GST_CLOCK_TIME_NONE;
28 h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE;
29 @@ -468,8 +466,15 @@ gst_h264_parse_process_nal (GstH264Parse
31 GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
32 h264parse->update_caps = TRUE;
33 - /* found in stream, no need to forcibly push at start */
34 - h264parse->push_codec = FALSE;
35 + h264parse->have_sps = TRUE;
36 + if (h264parse->push_codec && h264parse->have_pps) {
37 + /* SPS and PPS found in stream before the first pre_push_frame, no need
38 + * to forcibly push at start */
39 + GST_INFO_OBJECT (h264parse, "have SPS/PPS in stream");
40 + h264parse->push_codec = FALSE;
41 + h264parse->have_sps = FALSE;
42 + h264parse->have_pps = FALSE;
43 + }
45 gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu);
46 break;
47 @@ -478,8 +483,15 @@ gst_h264_parse_process_nal (GstH264Parse
48 /* parameters might have changed, force caps check */
49 GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
50 h264parse->update_caps = TRUE;
51 - /* found in stream, no need to forcibly push at start */
52 - h264parse->push_codec = FALSE;
53 + h264parse->have_pps = TRUE;
54 + if (h264parse->push_codec && h264parse->have_sps) {
55 + /* SPS and PPS found in stream before the first pre_push_frame, no need
56 + * to forcibly push at start */
57 + GST_INFO_OBJECT (h264parse, "have SPS/PPS in stream");
58 + h264parse->push_codec = FALSE;
59 + h264parse->have_sps = FALSE;
60 + h264parse->have_pps = FALSE;
61 + }
63 gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu);
64 break;
65 @@ -640,10 +652,12 @@ gst_h264_parse_check_valid_frame (GstBas
66 GstH264Parse *h264parse = GST_H264_PARSE (parse);
67 GstBuffer *buffer = frame->buffer;
68 guint8 *data;
69 - guint size, current_off = 0;
70 - gboolean drain;
71 + guint size;
72 + gint current_off = 0;
73 + gboolean drain, nonext;
74 GstH264NalParser *nalparser = h264parse->nalparser;
75 GstH264NalUnit nalu;
76 + GstH264ParserResult pres;
78 /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
79 if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
80 @@ -665,16 +679,39 @@ gst_h264_parse_check_valid_frame (GstBas
81 data = GST_BUFFER_DATA (buffer);
82 size = GST_BUFFER_SIZE (buffer);
84 - drain = FALSE;
85 - nalu = h264parse->nalu;
86 + drain = GST_BASE_PARSE_DRAINING (parse);
87 + nonext = FALSE;
89 current_off = h264parse->current_off;
90 + if (current_off < 0)
91 + current_off = 0;
93 g_assert (current_off < size);
94 + GST_DEBUG_OBJECT (h264parse, "last parse position %d", current_off);
96 - GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off);
97 - while (TRUE) {
98 - GstH264ParserResult pres;
99 + /* check for initial skip */
100 + if (h264parse->current_off == -1) {
101 + pres =
102 + gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
103 + size, &nalu);
104 + switch (pres) {
105 + case GST_H264_PARSER_OK:
106 + if (nalu.sc_offset > 0) {
107 + *skipsize = nalu.sc_offset;
108 + goto skip;
110 + break;
111 + case GST_H264_PARSER_NO_NAL:
112 + *skipsize = size - 3;
113 + goto skip;
114 + break;
115 + default:
116 + g_assert_not_reached ();
117 + break;
121 + while (TRUE) {
122 if (h264parse->packetized_chunked)
123 pres =
124 gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
125 @@ -686,99 +723,85 @@ gst_h264_parse_check_valid_frame (GstBas
127 switch (pres) {
128 case GST_H264_PARSER_OK:
129 - GST_DEBUG_OBJECT (h264parse, "complete nal found. "
130 - "current offset: %u, Nal offset: %u, Nal Size: %u",
131 - current_off, nalu.offset, nalu.size);
133 - GST_DEBUG_OBJECT (h264parse, "current off. %u",
134 - nalu.offset + nalu.size);
136 - if (!h264parse->nalu.size && !h264parse->nalu.valid)
137 - h264parse->nalu = nalu;
139 - /* need 2 bytes of next nal */
140 - if (!h264parse->packetized_chunked &&
141 - (nalu.offset + nalu.size + 4 + 2 > size)) {
142 - if (GST_BASE_PARSE_DRAINING (parse)) {
143 - drain = TRUE;
144 - } else {
145 - GST_DEBUG_OBJECT (h264parse, "need more bytes of next nal");
146 - current_off = nalu.sc_offset;
147 - goto more;
149 - } else if (h264parse->packetized_chunked) {
150 - /* normal next nal based collection not possible,
151 - * _chain will have to tell us whether this was last one for AU */
152 - drain = h264parse->packetized_last;
154 + GST_DEBUG_OBJECT (h264parse, "complete nal (offset, size): (%u, %u) ",
155 + nalu.offset, nalu.size);
156 break;
157 + case GST_H264_PARSER_NO_NAL_END:
158 + GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
159 + nalu.offset);
160 + /* if draining, accept it as complete nal */
161 + if (drain) {
162 + nonext = TRUE;
163 + nalu.size = size - nalu.offset;
164 + GST_DEBUG_OBJECT (h264parse, "draining, accepting with size %u",
165 + nalu.size);
166 + /* if it's not too short at least */
167 + if (nalu.size < 2)
168 + goto broken;
169 + break;
171 + /* otherwise need more */
172 + goto more;
173 case GST_H264_PARSER_BROKEN_LINK:
174 - return FALSE;
175 + g_assert_not_reached ();
176 + break;
177 case GST_H264_PARSER_ERROR:
178 - current_off = size - 3;
179 - goto parsing_error;
180 + /* should not really occur either */
181 + GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
182 + /* fall-through */
183 case GST_H264_PARSER_NO_NAL:
184 - /* don't expect to have found any NAL so far */
185 - g_assert (h264parse->nalu.size == 0);
186 - current_off = h264parse->nalu.sc_offset = size - 3;
187 - goto more;
188 + g_assert_not_reached ();
189 + break;
190 case GST_H264_PARSER_BROKEN_DATA:
191 GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
192 - "it contains a NAL unit of length %d", nalu.size);
194 + "it contains a NAL unit of length %u", nalu.size);
195 + broken:
196 /* broken nal at start -> arrange to skip it,
197 * otherwise have it terminate current au
198 * (and so it will be skipped on next frame round) */
199 - if (nalu.sc_offset == h264parse->nalu.sc_offset) {
200 - *skipsize = nalu.offset;
202 + if (current_off == 0) {
203 GST_DEBUG_OBJECT (h264parse, "skipping broken nal");
204 - goto invalid;
205 + *skipsize = nalu.offset;
206 + goto skip;
207 } else {
208 + GST_DEBUG_OBJECT (h264parse, "terminating au");
209 nalu.size = 0;
210 + nalu.offset = nalu.sc_offset;
211 goto end;
213 - case GST_H264_PARSER_NO_NAL_END:
214 - GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
215 - nalu.offset);
217 - current_off = nalu.sc_offset;
218 - /* We keep the reference to this nal so we start over the parsing
219 - * here */
220 - if (!h264parse->nalu.size && !h264parse->nalu.valid)
221 - h264parse->nalu = nalu;
223 - if (GST_BASE_PARSE_DRAINING (parse)) {
224 - drain = TRUE;
225 - GST_DEBUG_OBJECT (h264parse, "draining NAL %u %u %u", size,
226 - h264parse->nalu.offset, h264parse->nalu.size);
227 - /* Can't parse the nalu */
228 - if (size - h264parse->nalu.offset < 2) {
229 - *skipsize = nalu.offset;
230 - goto invalid;
233 - /* We parse it anyway */
234 - nalu.size = size - nalu.offset;
235 - break;
237 - goto more;
238 + break;
239 + default:
240 + g_assert_not_reached ();
241 + break;
244 - current_off = nalu.offset + nalu.size;
246 GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u",
247 data, nalu.offset, nalu.size);
249 + /* simulate no next nal if none needed */
250 + nonext = nonext || (h264parse->align == GST_H264_PARSE_ALIGN_NAL);
252 + if (!nonext && !h264parse->packetized_chunked) {
253 + if (nalu.offset + nalu.size + 4 + 2 > size) {
254 + GST_DEBUG_OBJECT (h264parse, "not enough data for next NALU");
255 + if (drain) {
256 + GST_DEBUG_OBJECT (h264parse, "but draining anyway");
257 + nonext = TRUE;
258 + } else {
259 + goto more;
264 gst_h264_parse_process_nal (h264parse, &nalu);
266 - /* simulate no next nal if none needed */
267 - drain = drain || (h264parse->align == GST_H264_PARSE_ALIGN_NAL);
268 + if (nonext)
269 + break;
271 /* In packetized mode we know there's only on NALU in each input packet,
272 * but we may not have seen the whole AU already, possibly need more */
273 if (h264parse->packetized_chunked) {
274 - if (drain)
275 + if (h264parse->packetized_last)
276 break;
277 /* next NALU expected at end of current data */
278 current_off = size;
279 @@ -786,42 +809,30 @@ gst_h264_parse_check_valid_frame (GstBas
282 /* if no next nal, we know it's complete here */
283 - if (drain || gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
284 + if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
285 break;
287 GST_DEBUG_OBJECT (h264parse, "Looking for more");
288 + current_off = nalu.offset + nalu.size;
291 end:
292 - *skipsize = h264parse->nalu.sc_offset;
293 - *framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset;
294 - h264parse->current_off = current_off;
296 + *framesize = nalu.offset + nalu.size;
297 return TRUE;
299 -parsing_error:
300 - GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
302 more:
303 /* ask for best next available */
304 *framesize = G_MAXUINT;
305 - if (!h264parse->nalu.size) {
306 - /* skip up to initial startcode */
307 - *skipsize = h264parse->nalu.sc_offset;
308 - /* but mind some stuff will have been skipped */
309 - g_assert (current_off >= *skipsize);
310 - current_off -= *skipsize;
311 - h264parse->nalu.sc_offset = 0;
312 - } else {
313 - *skipsize = 0;
315 + *skipsize = 0;
317 /* Restart parsing from here next time */
318 - h264parse->current_off = current_off;
319 + if (current_off > 0)
320 + h264parse->current_off = current_off;
322 return FALSE;
324 -invalid:
325 +skip:
326 + GST_DEBUG_OBJECT (h264parse, "skipping %d", *skipsize);
327 gst_h264_parse_reset_frame (h264parse);
328 return FALSE;
330 @@ -835,6 +846,7 @@ gst_h264_parse_make_codec_data (GstH264P
331 guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
332 gboolean found = FALSE;
333 guint8 *data;
334 + gint nl;
336 /* only nal payload in stored nals */
338 @@ -867,12 +879,13 @@ gst_h264_parse_make_codec_data (GstH264P
340 buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
341 data = GST_BUFFER_DATA (buf);
342 + nl = h264parse->nal_length_size;
344 data[0] = 1; /* AVC Decoder Configuration Record ver. 1 */
345 data[1] = profile_idc; /* profile_idc */
346 data[2] = profile_comp; /* profile_compability */
347 data[3] = level_idc; /* level_idc */
348 - data[4] = 0xfc | (4 - 1); /* nal_length_size_minus1 */
349 + data[4] = 0xfc | (nl - 1); /* nal_length_size_minus1 */
350 data[5] = 0xe0 | num_sps; /* number of SPSs */
352 data += 6;
353 @@ -1341,12 +1354,10 @@ check_pending_key_unit_event (GstEvent *
354 running_time < pending_key_unit_ts)
355 goto out;
357 -#if 0
358 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
359 GST_DEBUG ("pending force key unit, waiting for keyframe");
360 goto out;
362 -#endif
364 stream_time = gst_segment_to_stream_time (segment,
365 GST_FORMAT_TIME, timestamp);
366 @@ -1479,32 +1490,38 @@ gst_h264_parse_pre_push_frame (GstBasePa
367 GstByteWriter bw;
368 GstBuffer *new_buf;
369 const gboolean bs = h264parse->format == GST_H264_PARSE_FORMAT_BYTE;
370 + const gint nls = 4 - h264parse->nal_length_size;
371 + gboolean ok;
373 gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buffer), FALSE);
374 - gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
375 + ok = gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
376 h264parse->idr_pos);
377 GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
378 for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
379 if ((codec_nal = h264parse->sps_nals[i])) {
380 GST_DEBUG_OBJECT (h264parse, "inserting SPS nal");
381 - gst_byte_writer_put_uint32_be (&bw,
382 - bs ? 1 : GST_BUFFER_SIZE (codec_nal));
383 - gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal),
384 - GST_BUFFER_SIZE (codec_nal));
385 + ok &= gst_byte_writer_put_uint32_be (&bw,
386 + bs ? 1 : (GST_BUFFER_SIZE (codec_nal) << (nls * 8)));
387 + ok &= gst_byte_writer_set_pos (&bw,
388 + gst_byte_writer_get_pos (&bw) - nls);
389 + ok &= gst_byte_writer_put_data (&bw,
390 + GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal));
391 h264parse->last_report = new_ts;
394 for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
395 if ((codec_nal = h264parse->pps_nals[i])) {
396 GST_DEBUG_OBJECT (h264parse, "inserting PPS nal");
397 - gst_byte_writer_put_uint32_be (&bw,
398 - bs ? 1 : GST_BUFFER_SIZE (codec_nal));
399 - gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal),
400 - GST_BUFFER_SIZE (codec_nal));
401 + ok &= gst_byte_writer_put_uint32_be (&bw,
402 + bs ? 1 : (GST_BUFFER_SIZE (codec_nal) << (nls * 8)));
403 + ok &= gst_byte_writer_set_pos (&bw,
404 + gst_byte_writer_get_pos (&bw) - nls);
405 + ok &= gst_byte_writer_put_data (&bw,
406 + GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal));
407 h264parse->last_report = new_ts;
410 - gst_byte_writer_put_data (&bw,
411 + ok &= gst_byte_writer_put_data (&bw,
412 GST_BUFFER_DATA (buffer) + h264parse->idr_pos,
413 GST_BUFFER_SIZE (buffer) - h264parse->idr_pos);
414 /* collect result and push */
415 @@ -1515,10 +1532,16 @@ gst_h264_parse_pre_push_frame (GstBasePa
416 GST_BUFFER_FLAG_UNSET (new_buf, GST_BUFFER_FLAG_DELTA_UNIT);
417 gst_buffer_replace (&frame->buffer, new_buf);
418 gst_buffer_unref (new_buf);
419 + /* some result checking seems to make some compilers happy */
420 + if (G_UNLIKELY (!ok)) {
421 + GST_ERROR_OBJECT (h264parse, "failed to insert SPS/PPS");
425 /* we pushed whatever we had */
426 h264parse->push_codec = FALSE;
427 + h264parse->have_sps = FALSE;
428 + h264parse->have_pps = FALSE;
432 @@ -1623,10 +1646,10 @@ gst_h264_parse_set_caps (GstBaseParse *
434 /* if upstream sets codec_data without setting stream-format and alignment, we
435 * assume stream-format=avc,alignment=au */
436 - if (format == GST_H264_PARSE_FORMAT_NONE) {
437 + if (format == GST_H264_PARSE_FORMAT_NONE)
438 format = GST_H264_PARSE_FORMAT_AVC;
439 + if (align == GST_H264_PARSE_ALIGN_NONE)
440 align = GST_H264_PARSE_ALIGN_AU;
442 } else {
443 GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
444 /* nothing to pre-process */
445 @@ -1665,6 +1688,8 @@ gst_h264_parse_set_caps (GstBaseParse *
446 /* arrange to insert codec-data in-stream if needed.
447 * src caps are only arranged for later on */
448 h264parse->push_codec = TRUE;
449 + h264parse->have_sps = FALSE;
450 + h264parse->have_pps = FALSE;
451 h264parse->split_packetized = TRUE;
452 h264parse->packetized = TRUE;
454 --- gst-plugins-bad0.10-0.10.23.orig/gst/videoparsers/gsth264parse.h
455 +++ gst-plugins-bad0.10-0.10.23/gst/videoparsers/gsth264parse.h
456 @@ -67,15 +67,16 @@ struct _GstH264Parse
458 /* state */
459 GstH264NalParser *nalparser;
460 - GstH264NalUnit nalu;
461 guint align;
462 guint format;
463 - guint current_off;
464 + gint current_off;
465 gboolean packetized_last;
466 gboolean packetized_chunked;
468 GstClockTime last_report;
469 gboolean push_codec;
470 + gboolean have_sps;
471 + gboolean have_pps;
473 /* collected SPS and PPS NALUs */
474 GstBuffer *sps_nals[GST_H264_MAX_SPS_COUNT];