diff -Nru gst-plugins-bad0.10-0.10.23/debian/changelog gst-plugins-bad0.10-0.10.23/debian/changelog --- gst-plugins-bad0.10-0.10.23/debian/changelog 2012-09-15 13:44:09.000000000 +0200 +++ gst-plugins-bad0.10-0.10.23/debian/changelog 2012-11-15 14:15:52.000000000 +0100 @@ -1,3 +1,10 @@ +gst-plugins-bad0.10 (0.10.23-7ubuntu2) raring; urgency=low + + * Really fix h264 parsing. Thanks to Doug McMahon and other people + commenting in (LP: #973014) for providing this fix. + + -- David Henningsson Wed, 10 Oct 2012 12:01:06 +0200 + gst-plugins-bad0.10 (0.10.23-7ubuntu1) quantal; urgency=low * Resynchronize with Debian wheezy (LP: #1051153). Remaining changes: diff -Nru gst-plugins-bad0.10-0.10.23/debian/patches/really-fix-h264-parsing.patch gst-plugins-bad0.10-0.10.23/debian/patches/really-fix-h264-parsing.patch --- gst-plugins-bad0.10-0.10.23/debian/patches/really-fix-h264-parsing.patch 1970-01-01 01:00:00.000000000 +0100 +++ gst-plugins-bad0.10-0.10.23/debian/patches/really-fix-h264-parsing.patch 2012-11-15 14:18:06.000000000 +0100 @@ -0,0 +1,474 @@ +# Description: Fixes failure to decode many common video files encoded as AVC 1 Baseline - L2.1, Baseline - L1.1 & others +# Forwarded: not-needed +# Origin: upstream +# Bug-Ubuntu: https://bugs.launchpad.net/bugs/973014 +--- gst-plugins-bad0.10-0.10.23.orig/gst/videoparsers/gsth264parse.c ++++ gst-plugins-bad0.10-0.10.23/gst/videoparsers/gsth264parse.c +@@ -177,11 +177,7 @@ gst_h264_parse_reset_frame (GstH264Parse + GST_DEBUG_OBJECT (h264parse, "reset frame"); + + /* done parsing; reset state */ +- h264parse->nalu.valid = FALSE; +- h264parse->nalu.offset = 0; +- h264parse->nalu.sc_offset = 0; +- h264parse->nalu.size = 0; +- h264parse->current_off = 0; ++ h264parse->current_off = -1; + + h264parse->picture_start = FALSE; + h264parse->update_caps = FALSE; +@@ -213,6 +209,8 @@ gst_h264_parse_reset (GstH264Parse * h26 + + h264parse->last_report = GST_CLOCK_TIME_NONE; + h264parse->push_codec = FALSE; ++ h264parse->have_pps = FALSE; ++ h264parse->have_sps = FALSE; + + h264parse->dts = GST_CLOCK_TIME_NONE; + h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE; +@@ -468,8 +466,15 @@ gst_h264_parse_process_nal (GstH264Parse + + GST_DEBUG_OBJECT (h264parse, "triggering src caps check"); + h264parse->update_caps = TRUE; +- /* found in stream, no need to forcibly push at start */ +- h264parse->push_codec = FALSE; ++ h264parse->have_sps = TRUE; ++ if (h264parse->push_codec && h264parse->have_pps) { ++ /* SPS and PPS found in stream before the first pre_push_frame, no need ++ * to forcibly push at start */ ++ GST_INFO_OBJECT (h264parse, "have SPS/PPS in stream"); ++ h264parse->push_codec = FALSE; ++ h264parse->have_sps = FALSE; ++ h264parse->have_pps = FALSE; ++ } + + gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu); + break; +@@ -478,8 +483,15 @@ gst_h264_parse_process_nal (GstH264Parse + /* parameters might have changed, force caps check */ + GST_DEBUG_OBJECT (h264parse, "triggering src caps check"); + h264parse->update_caps = TRUE; +- /* found in stream, no need to forcibly push at start */ +- h264parse->push_codec = FALSE; ++ h264parse->have_pps = TRUE; ++ if (h264parse->push_codec && h264parse->have_sps) { ++ /* SPS and PPS found in stream before the first pre_push_frame, no need ++ * to forcibly push at start */ ++ GST_INFO_OBJECT (h264parse, "have SPS/PPS in stream"); ++ h264parse->push_codec = FALSE; ++ h264parse->have_sps = FALSE; ++ h264parse->have_pps = FALSE; ++ } + + gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu); + break; +@@ -640,10 +652,12 @@ gst_h264_parse_check_valid_frame (GstBas + GstH264Parse *h264parse = GST_H264_PARSE (parse); + GstBuffer *buffer = frame->buffer; + guint8 *data; +- guint size, current_off = 0; +- gboolean drain; ++ guint size; ++ gint current_off = 0; ++ gboolean drain, nonext; + GstH264NalParser *nalparser = h264parse->nalparser; + GstH264NalUnit nalu; ++ GstH264ParserResult pres; + + /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */ + if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5)) +@@ -665,16 +679,39 @@ gst_h264_parse_check_valid_frame (GstBas + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + +- drain = FALSE; +- nalu = h264parse->nalu; ++ drain = GST_BASE_PARSE_DRAINING (parse); ++ nonext = FALSE; ++ + current_off = h264parse->current_off; ++ if (current_off < 0) ++ current_off = 0; + + g_assert (current_off < size); ++ GST_DEBUG_OBJECT (h264parse, "last parse position %d", current_off); + +- GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off); +- while (TRUE) { +- GstH264ParserResult pres; ++ /* check for initial skip */ ++ if (h264parse->current_off == -1) { ++ pres = ++ gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off, ++ size, &nalu); ++ switch (pres) { ++ case GST_H264_PARSER_OK: ++ if (nalu.sc_offset > 0) { ++ *skipsize = nalu.sc_offset; ++ goto skip; ++ } ++ break; ++ case GST_H264_PARSER_NO_NAL: ++ *skipsize = size - 3; ++ goto skip; ++ break; ++ default: ++ g_assert_not_reached (); ++ break; ++ } ++ } + ++ while (TRUE) { + if (h264parse->packetized_chunked) + pres = + gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off, +@@ -686,99 +723,85 @@ gst_h264_parse_check_valid_frame (GstBas + + switch (pres) { + case GST_H264_PARSER_OK: +- GST_DEBUG_OBJECT (h264parse, "complete nal found. " +- "current offset: %u, Nal offset: %u, Nal Size: %u", +- current_off, nalu.offset, nalu.size); +- +- GST_DEBUG_OBJECT (h264parse, "current off. %u", +- nalu.offset + nalu.size); +- +- if (!h264parse->nalu.size && !h264parse->nalu.valid) +- h264parse->nalu = nalu; +- +- /* need 2 bytes of next nal */ +- if (!h264parse->packetized_chunked && +- (nalu.offset + nalu.size + 4 + 2 > size)) { +- if (GST_BASE_PARSE_DRAINING (parse)) { +- drain = TRUE; +- } else { +- GST_DEBUG_OBJECT (h264parse, "need more bytes of next nal"); +- current_off = nalu.sc_offset; +- goto more; +- } +- } else if (h264parse->packetized_chunked) { +- /* normal next nal based collection not possible, +- * _chain will have to tell us whether this was last one for AU */ +- drain = h264parse->packetized_last; +- } ++ GST_DEBUG_OBJECT (h264parse, "complete nal (offset, size): (%u, %u) ", ++ nalu.offset, nalu.size); + break; ++ case GST_H264_PARSER_NO_NAL_END: ++ GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u", ++ nalu.offset); ++ /* if draining, accept it as complete nal */ ++ if (drain) { ++ nonext = TRUE; ++ nalu.size = size - nalu.offset; ++ GST_DEBUG_OBJECT (h264parse, "draining, accepting with size %u", ++ nalu.size); ++ /* if it's not too short at least */ ++ if (nalu.size < 2) ++ goto broken; ++ break; ++ } ++ /* otherwise need more */ ++ goto more; + case GST_H264_PARSER_BROKEN_LINK: +- return FALSE; ++ g_assert_not_reached (); ++ break; + case GST_H264_PARSER_ERROR: +- current_off = size - 3; +- goto parsing_error; ++ /* should not really occur either */ ++ GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit"); ++ /* fall-through */ + case GST_H264_PARSER_NO_NAL: +- /* don't expect to have found any NAL so far */ +- g_assert (h264parse->nalu.size == 0); +- current_off = h264parse->nalu.sc_offset = size - 3; +- goto more; ++ g_assert_not_reached (); ++ break; + case GST_H264_PARSER_BROKEN_DATA: + GST_WARNING_OBJECT (h264parse, "input stream is corrupt; " +- "it contains a NAL unit of length %d", nalu.size); +- ++ "it contains a NAL unit of length %u", nalu.size); ++ broken: + /* broken nal at start -> arrange to skip it, + * otherwise have it terminate current au + * (and so it will be skipped on next frame round) */ +- if (nalu.sc_offset == h264parse->nalu.sc_offset) { +- *skipsize = nalu.offset; +- ++ if (current_off == 0) { + GST_DEBUG_OBJECT (h264parse, "skipping broken nal"); +- goto invalid; ++ *skipsize = nalu.offset; ++ goto skip; + } else { ++ GST_DEBUG_OBJECT (h264parse, "terminating au"); + nalu.size = 0; ++ nalu.offset = nalu.sc_offset; + goto end; + } +- case GST_H264_PARSER_NO_NAL_END: +- GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u", +- nalu.offset); +- +- current_off = nalu.sc_offset; +- /* We keep the reference to this nal so we start over the parsing +- * here */ +- if (!h264parse->nalu.size && !h264parse->nalu.valid) +- h264parse->nalu = nalu; +- +- if (GST_BASE_PARSE_DRAINING (parse)) { +- drain = TRUE; +- GST_DEBUG_OBJECT (h264parse, "draining NAL %u %u %u", size, +- h264parse->nalu.offset, h264parse->nalu.size); +- /* Can't parse the nalu */ +- if (size - h264parse->nalu.offset < 2) { +- *skipsize = nalu.offset; +- goto invalid; +- } +- +- /* We parse it anyway */ +- nalu.size = size - nalu.offset; +- break; +- } +- goto more; ++ break; ++ default: ++ g_assert_not_reached (); ++ break; + } + +- current_off = nalu.offset + nalu.size; +- + GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u", + data, nalu.offset, nalu.size); + ++ /* simulate no next nal if none needed */ ++ nonext = nonext || (h264parse->align == GST_H264_PARSE_ALIGN_NAL); ++ ++ if (!nonext && !h264parse->packetized_chunked) { ++ if (nalu.offset + nalu.size + 4 + 2 > size) { ++ GST_DEBUG_OBJECT (h264parse, "not enough data for next NALU"); ++ if (drain) { ++ GST_DEBUG_OBJECT (h264parse, "but draining anyway"); ++ nonext = TRUE; ++ } else { ++ goto more; ++ } ++ } ++ } ++ + gst_h264_parse_process_nal (h264parse, &nalu); + +- /* simulate no next nal if none needed */ +- drain = drain || (h264parse->align == GST_H264_PARSE_ALIGN_NAL); ++ if (nonext) ++ break; + + /* In packetized mode we know there's only on NALU in each input packet, + * but we may not have seen the whole AU already, possibly need more */ + if (h264parse->packetized_chunked) { +- if (drain) ++ if (h264parse->packetized_last) + break; + /* next NALU expected at end of current data */ + current_off = size; +@@ -786,42 +809,30 @@ gst_h264_parse_check_valid_frame (GstBas + } + + /* if no next nal, we know it's complete here */ +- if (drain || gst_h264_parse_collect_nal (h264parse, data, size, &nalu)) ++ if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu)) + break; + + GST_DEBUG_OBJECT (h264parse, "Looking for more"); ++ current_off = nalu.offset + nalu.size; + } + + end: +- *skipsize = h264parse->nalu.sc_offset; +- *framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset; +- h264parse->current_off = current_off; +- ++ *framesize = nalu.offset + nalu.size; + return TRUE; + +-parsing_error: +- GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit"); +- + more: + /* ask for best next available */ + *framesize = G_MAXUINT; +- if (!h264parse->nalu.size) { +- /* skip up to initial startcode */ +- *skipsize = h264parse->nalu.sc_offset; +- /* but mind some stuff will have been skipped */ +- g_assert (current_off >= *skipsize); +- current_off -= *skipsize; +- h264parse->nalu.sc_offset = 0; +- } else { +- *skipsize = 0; +- } ++ *skipsize = 0; + + /* Restart parsing from here next time */ +- h264parse->current_off = current_off; ++ if (current_off > 0) ++ h264parse->current_off = current_off; + + return FALSE; + +-invalid: ++skip: ++ GST_DEBUG_OBJECT (h264parse, "skipping %d", *skipsize); + gst_h264_parse_reset_frame (h264parse); + return FALSE; + } +@@ -835,6 +846,7 @@ gst_h264_parse_make_codec_data (GstH264P + guint8 profile_idc = 0, profile_comp = 0, level_idc = 0; + gboolean found = FALSE; + guint8 *data; ++ gint nl; + + /* only nal payload in stored nals */ + +@@ -867,12 +879,13 @@ gst_h264_parse_make_codec_data (GstH264P + + buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size); + data = GST_BUFFER_DATA (buf); ++ nl = h264parse->nal_length_size; + + data[0] = 1; /* AVC Decoder Configuration Record ver. 1 */ + data[1] = profile_idc; /* profile_idc */ + data[2] = profile_comp; /* profile_compability */ + data[3] = level_idc; /* level_idc */ +- data[4] = 0xfc | (4 - 1); /* nal_length_size_minus1 */ ++ data[4] = 0xfc | (nl - 1); /* nal_length_size_minus1 */ + data[5] = 0xe0 | num_sps; /* number of SPSs */ + + data += 6; +@@ -1341,12 +1354,10 @@ check_pending_key_unit_event (GstEvent * + running_time < pending_key_unit_ts) + goto out; + +-#if 0 + if (flags & GST_BUFFER_FLAG_DELTA_UNIT) { + GST_DEBUG ("pending force key unit, waiting for keyframe"); + goto out; + } +-#endif + + stream_time = gst_segment_to_stream_time (segment, + GST_FORMAT_TIME, timestamp); +@@ -1479,32 +1490,38 @@ gst_h264_parse_pre_push_frame (GstBasePa + GstByteWriter bw; + GstBuffer *new_buf; + const gboolean bs = h264parse->format == GST_H264_PARSE_FORMAT_BYTE; ++ const gint nls = 4 - h264parse->nal_length_size; ++ gboolean ok; + + gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buffer), FALSE); +- gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer), ++ ok = gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer), + h264parse->idr_pos); + GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS"); + for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) { + if ((codec_nal = h264parse->sps_nals[i])) { + GST_DEBUG_OBJECT (h264parse, "inserting SPS nal"); +- gst_byte_writer_put_uint32_be (&bw, +- bs ? 1 : GST_BUFFER_SIZE (codec_nal)); +- gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal), +- GST_BUFFER_SIZE (codec_nal)); ++ ok &= gst_byte_writer_put_uint32_be (&bw, ++ bs ? 1 : (GST_BUFFER_SIZE (codec_nal) << (nls * 8))); ++ ok &= gst_byte_writer_set_pos (&bw, ++ gst_byte_writer_get_pos (&bw) - nls); ++ ok &= gst_byte_writer_put_data (&bw, ++ GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal)); + h264parse->last_report = new_ts; + } + } + for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) { + if ((codec_nal = h264parse->pps_nals[i])) { + GST_DEBUG_OBJECT (h264parse, "inserting PPS nal"); +- gst_byte_writer_put_uint32_be (&bw, +- bs ? 1 : GST_BUFFER_SIZE (codec_nal)); +- gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal), +- GST_BUFFER_SIZE (codec_nal)); ++ ok &= gst_byte_writer_put_uint32_be (&bw, ++ bs ? 1 : (GST_BUFFER_SIZE (codec_nal) << (nls * 8))); ++ ok &= gst_byte_writer_set_pos (&bw, ++ gst_byte_writer_get_pos (&bw) - nls); ++ ok &= gst_byte_writer_put_data (&bw, ++ GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal)); + h264parse->last_report = new_ts; + } + } +- gst_byte_writer_put_data (&bw, ++ ok &= gst_byte_writer_put_data (&bw, + GST_BUFFER_DATA (buffer) + h264parse->idr_pos, + GST_BUFFER_SIZE (buffer) - h264parse->idr_pos); + /* collect result and push */ +@@ -1515,10 +1532,16 @@ gst_h264_parse_pre_push_frame (GstBasePa + GST_BUFFER_FLAG_UNSET (new_buf, GST_BUFFER_FLAG_DELTA_UNIT); + gst_buffer_replace (&frame->buffer, new_buf); + gst_buffer_unref (new_buf); ++ /* some result checking seems to make some compilers happy */ ++ if (G_UNLIKELY (!ok)) { ++ GST_ERROR_OBJECT (h264parse, "failed to insert SPS/PPS"); ++ } + } + } + /* we pushed whatever we had */ + h264parse->push_codec = FALSE; ++ h264parse->have_sps = FALSE; ++ h264parse->have_pps = FALSE; + } + } + +@@ -1623,10 +1646,10 @@ gst_h264_parse_set_caps (GstBaseParse * + + /* if upstream sets codec_data without setting stream-format and alignment, we + * assume stream-format=avc,alignment=au */ +- if (format == GST_H264_PARSE_FORMAT_NONE) { ++ if (format == GST_H264_PARSE_FORMAT_NONE) + format = GST_H264_PARSE_FORMAT_AVC; ++ if (align == GST_H264_PARSE_ALIGN_NONE) + align = GST_H264_PARSE_ALIGN_AU; +- } + } else { + GST_DEBUG_OBJECT (h264parse, "have bytestream h264"); + /* nothing to pre-process */ +@@ -1665,6 +1688,8 @@ gst_h264_parse_set_caps (GstBaseParse * + /* arrange to insert codec-data in-stream if needed. + * src caps are only arranged for later on */ + h264parse->push_codec = TRUE; ++ h264parse->have_sps = FALSE; ++ h264parse->have_pps = FALSE; + h264parse->split_packetized = TRUE; + h264parse->packetized = TRUE; + } +--- gst-plugins-bad0.10-0.10.23.orig/gst/videoparsers/gsth264parse.h ++++ gst-plugins-bad0.10-0.10.23/gst/videoparsers/gsth264parse.h +@@ -67,15 +67,16 @@ struct _GstH264Parse + + /* state */ + GstH264NalParser *nalparser; +- GstH264NalUnit nalu; + guint align; + guint format; +- guint current_off; ++ gint current_off; + gboolean packetized_last; + gboolean packetized_chunked; + + GstClockTime last_report; + gboolean push_codec; ++ gboolean have_sps; ++ gboolean have_pps; + + /* collected SPS and PPS NALUs */ + GstBuffer *sps_nals[GST_H264_MAX_SPS_COUNT]; diff -Nru gst-plugins-bad0.10-0.10.23/debian/patches/series gst-plugins-bad0.10-0.10.23/debian/patches/series --- gst-plugins-bad0.10-0.10.23/debian/patches/series 2012-09-15 13:44:09.000000000 +0200 +++ gst-plugins-bad0.10-0.10.23/debian/patches/series 2012-11-15 14:15:52.000000000 +0100 @@ -11,5 +11,5 @@ 0017-opusdec-read-gain-from-the-right-place-in-the-header.patch 0020-opusenc-add-missing-mutex-unlock-on-error-path.patch glib-single-include -fix-h264-parsing.patch +really-fix-h264-parsing.patch vp8-realtime-preset.patch