X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=subprojects%2Fgst-plugins-good%2Fgst%2Fisomp4%2Fqtdemux.c;h=b20c25565640bd84a999fefd4040e772aff5df48;hb=cab020b4cb5418359c13409a115c844b80d9c06f;hp=7cc346b1e634492549ab8d510ab7c994fafa5918;hpb=7273024ae503f2bdcbb911c164cc637781c4ce98;p=platform%2Fupstream%2Fgstreamer.git diff --git a/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c b/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c index 7cc346b..b20c255 100644 --- a/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c +++ b/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c @@ -392,6 +392,8 @@ static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux, const gchar * id); static void qtdemux_gst_structure_free (GstStructure * gststructure); static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard); +static void qtdemux_clear_protection_events_on_all_streams (GstQTDemux * + qtdemux); static void gst_qtdemux_class_init (GstQTDemuxClass * klass) @@ -482,9 +484,8 @@ gst_qtdemux_dispose (GObject * object) } gst_tag_list_unref (qtdemux->tag_list); gst_flow_combiner_free (qtdemux->flowcombiner); - g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref, - NULL); - g_queue_clear (&qtdemux->protection_event_queue); + g_queue_clear_full (&qtdemux->protection_event_queue, + (GDestroyNotify) gst_event_unref); g_free (qtdemux->cenc_aux_info_sizes); qtdemux->cenc_aux_info_sizes = NULL; @@ -1985,7 +1986,6 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) gint i; GST_DEBUG_OBJECT (qtdemux, "Resetting demux"); - gst_pad_stop_task (qtdemux->sinkpad); if (hard || qtdemux->upstream_format_is_time) { qtdemux->state = QTDEMUX_STATE_INITIAL; @@ -2040,9 +2040,8 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) qtdemux->have_group_id = FALSE; qtdemux->group_id = G_MAXUINT; - g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref, - NULL); - g_queue_clear (&qtdemux->protection_event_queue); + g_queue_clear_full (&qtdemux->protection_event_queue, + (GDestroyNotify) gst_event_unref); qtdemux->received_seek = FALSE; qtdemux->first_moof_already_parsed = FALSE; @@ -2067,7 +2066,9 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) gst_caps_replace (&qtdemux->media_caps, NULL); qtdemux->timescale = 0; qtdemux->got_moov = FALSE; + qtdemux->start_utc_time = GST_CLOCK_TIME_NONE; qtdemux->cenc_aux_info_offset = 0; + g_free (qtdemux->cenc_aux_info_sizes); qtdemux->cenc_aux_info_sizes = NULL; qtdemux->cenc_aux_sample_count = 0; if (qtdemux->protection_system_ids) { @@ -2098,6 +2099,15 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) } } +static void +qtdemux_clear_protection_events_on_all_streams (GstQTDemux * qtdemux) +{ + for (unsigned i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) { + QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i); + g_queue_clear_full (&stream->protection_scheme_event_queue, + (GDestroyNotify) gst_event_unref); + } +} /* Maps the @segment to the qt edts internal segments and pushes * the corresponding segment event. @@ -2573,9 +2583,8 @@ gst_qtdemux_stream_clear (QtDemuxStream * stream) } stream->protection_scheme_type = 0; stream->protection_scheme_version = 0; - g_queue_foreach (&stream->protection_scheme_event_queue, - (GFunc) gst_event_unref, NULL); - g_queue_clear (&stream->protection_scheme_event_queue); + g_queue_clear_full (&stream->protection_scheme_event_queue, + (GDestroyNotify) gst_event_unref); gst_qtdemux_stream_flush_segments_data (stream); gst_qtdemux_stream_flush_samples_data (stream); } @@ -2842,8 +2851,13 @@ qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length, return; } - gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, - G_TYPE_STRING, &system_id, NULL); + if (!gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, + G_TYPE_STRING, &system_id, NULL)) { + GST_WARNING_OBJECT (qtdemux, "%s field not present in caps", + GST_PROTECTION_SYSTEM_ID_CAPS_FIELD); + return; + } + gst_qtdemux_append_protection_system_id (qtdemux, system_id); stream->protected = TRUE; @@ -3054,9 +3068,60 @@ qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length) gst_isoff_qt_sidx_parser_clear (&sidx_parser); } +static void +qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data) +{ + guint64 start_time; + guint32 entry_count; + + GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box"); + + qtdemux->start_utc_time = GST_CLOCK_TIME_NONE; + + if (gst_byte_reader_get_remaining (data) < 4) { + GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box"); + return; + } + + entry_count = gst_byte_reader_get_uint32_be_unchecked (data); + if (entry_count == 0) + return; + + /* XXX: We assume that all start times are the same as different start times + * would violate the MP4 synchronization model, so we just take the first + * one here and apply it to all tracks. + */ + + if (gst_byte_reader_get_remaining (data) < entry_count * 12) { + GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box"); + return; + } + + /* Skip track id */ + gst_byte_reader_skip_unchecked (data, 4); + + /* In 100ns intervals */ + start_time = gst_byte_reader_get_uint64_be_unchecked (data); + + /* Convert from Jan 1 1601 to Jan 1 1970 */ + if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) { + GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch"); + return; + } + start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000); + + /* Convert to GstClockTime */ + start_time *= 100; + + GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (start_time)); + + qtdemux->start_utc_time = start_time; +} + /* caller verifies at least 8 bytes in buf */ static void -extract_initial_length_and_fourcc (const guint8 * data, guint size, +extract_initial_length_and_fourcc (const guint8 * data, gsize size, guint64 * plength, guint32 * pfourcc) { guint64 length; @@ -3412,33 +3477,22 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_ts)); } else { - /* subsequent fragments extend stream */ - timestamp = - stream->samples[stream->n_samples - 1].timestamp + - stream->samples[stream->n_samples - 1].duration; - - /* If this is a GST_FORMAT_BYTES stream and there's a significant - * difference (1 sec.) between decode_ts and timestamp, prefer the - * former */ - if (has_tfdt && !qtdemux->upstream_format_is_time - && ABSDIFF (decode_ts, timestamp) > - MAX (stream->duration_last_moof / 2, - GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) { - GST_INFO_OBJECT (qtdemux, - "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT - ") are significantly different (more than %" GST_TIME_FORMAT - "), using decode_ts", - GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)), - GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)), - GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, - MAX (stream->duration_last_moof / 2, - GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))))); + /* If this is a GST_FORMAT_BYTES stream and we have a tfdt then use it + * instead of the sum of sample durations */ + if (has_tfdt && !qtdemux->upstream_format_is_time) { timestamp = decode_ts; + gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp); + GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT + " (using tfdt)", GST_TIME_ARGS (gst_ts)); + } else { + /* subsequent fragments extend stream */ + timestamp = + stream->samples[stream->n_samples - 1].timestamp + + stream->samples[stream->n_samples - 1].duration; + gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp); + GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT + " (extends previous samples)", GST_TIME_ARGS (gst_ts)); } - - gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp); - GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT - " (extends previous samples)", GST_TIME_ARGS (gst_ts)); } } @@ -3627,11 +3681,13 @@ qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd, goto invalid_track; /* obtain stream defaults */ - qtdemux_parse_trex (qtdemux, *stream, - default_sample_duration, default_sample_size, default_sample_flags); + if (qtdemux_parse_trex (qtdemux, *stream, + default_sample_duration, default_sample_size, default_sample_flags)) { - (*stream)->stsd_sample_description_id = - (*stream)->def_sample_description_index - 1; + /* Default sample description index is only valid if trex parsing succeeded */ + (*stream)->stsd_sample_description_id = + (*stream)->def_sample_description_index - 1; + } if (flags & TF_SAMPLE_DESCRIPTION_INDEX) { guint32 sample_description_index; @@ -4233,6 +4289,10 @@ qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length, /* parse any protection system info */ pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh); + if (pssh_node) { + /* Unref old protection events if we are going to receive new ones. */ + qtdemux_clear_protection_events_on_all_streams (qtdemux); + } while (pssh_node) { GST_LOG_OBJECT (qtdemux, "Parsing pssh box."); qtdemux_parse_pssh (qtdemux, pssh_node); @@ -4616,8 +4676,8 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX, (_("This file is incomplete and cannot be played.")), ("We got less than expected (received %" G_GSIZE_FORMAT - ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size, - (guint) length, cur_offset)); + ", wanted %" G_GUINT64_FORMAT ", offset %" G_GUINT64_FORMAT ")", + map.size, length, cur_offset)); gst_buffer_unmap (moov, &map); gst_buffer_unref (moov); ret = GST_FLOW_ERROR; @@ -4699,6 +4759,34 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) gst_buffer_unref (sidx); break; } + case FOURCC_meta: + { + GstBuffer *meta = NULL; + GNode *node, *child; + GstByteReader child_data; + ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta); + if (ret != GST_FLOW_OK) + goto beach; + qtdemux->offset += length; + gst_buffer_map (meta, &map, GST_MAP_READ); + + node = g_node_new (map.data); + + qtdemux_parse_node (qtdemux, node, map.data, map.size); + + /* Parse ONVIF Export File Format CorrectStartTime box if available */ + if ((child = + qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb, + &child_data))) { + qtdemux_parse_cstb (qtdemux, &child_data); + } + + g_node_destroy (node); + + gst_buffer_unmap (meta, &map); + gst_buffer_unref (meta); + break; + } default: { GstBuffer *unknown = NULL; @@ -6208,6 +6296,15 @@ gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux, /* we're going to modify the metadata */ buf = gst_buffer_make_writable (buf); + if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) { + static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix"); + GstCaps *caps = gst_static_caps_get (&unix_caps); + gst_buffer_add_reference_timestamp_meta (buf, caps, + pts + qtdemux->start_utc_time - stream->cslg_shift, + GST_CLOCK_TIME_NONE); + gst_caps_unref (caps); + } + GST_BUFFER_DTS (buf) = dts; GST_BUFFER_PTS (buf) = pts; GST_BUFFER_DURATION (buf) = duration; @@ -6484,6 +6581,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) /* send gap events until the stream catches up */ /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */ while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) && + pseudo_cur_time < (G_MAXUINT64 - gap_threshold) && pseudo_cur_time + gap_threshold < pseudo_target_time) { GstEvent *gap = gst_event_new_gap (stream->segment.position, gap_threshold); @@ -7351,6 +7449,7 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) if (demux->moov_node) g_node_destroy (demux->moov_node); demux->moov_node = NULL; + demux->start_utc_time = GST_CLOCK_TIME_NONE; } demux->last_moov_offset = demux->offset; @@ -7473,6 +7572,21 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) } else if (fourcc == FOURCC_sidx) { GST_DEBUG_OBJECT (demux, "Parsing [sidx]"); qtdemux_parse_sidx (demux, data, demux->neededbytes); + } else if (fourcc == FOURCC_meta) { + GNode *node, *child; + GstByteReader child_data; + + node = g_node_new ((gpointer) data); + qtdemux_parse_node (demux, node, data, demux->neededbytes); + + /* Parse ONVIF Export File Format CorrectStartTime box if available */ + if ((child = + qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb, + &child_data))) { + qtdemux_parse_cstb (demux, &child_data); + } + + g_node_destroy (node); } else { switch (fourcc) { case FOURCC_styp: @@ -7905,10 +8019,16 @@ qtdemux_inflate (void *z_buffer, guint z_length, guint * length) break; } + if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) { + GST_WARNING ("too big decompressed data"); + ret = Z_MEM_ERROR; + break; + } + *length += 4096; buffer = (guint8 *) g_realloc (buffer, *length); z.next_out = (Bytef *) (buffer + z.total_out); - z.avail_out += 4096; + z.avail_out += *length - z.total_out; } while (z.avail_in > 0); if (ret != Z_STREAM_END) { @@ -8503,10 +8623,10 @@ gst_qtdemux_request_protection_context (GstQTDemux * qtdemux, g_value_init (&event_list, GST_TYPE_LIST); for (; walk; walk = g_list_previous (walk)) { - GValue *event_value = g_new0 (GValue, 1); - g_value_init (event_value, GST_TYPE_EVENT); - g_value_set_boxed (event_value, walk->data); - gst_value_list_append_and_take_value (&event_list, event_value); + GValue event_value = G_VALUE_INIT; + g_value_init (&event_value, GST_TYPE_EVENT); + g_value_set_boxed (&event_value, walk->data); + gst_value_list_append_and_take_value (&event_list, &event_value); } /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and @@ -10152,8 +10272,8 @@ qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream, stream->segments = NULL; if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) { GNode *elst; - gint n_segments; - gint segment_number, entry_size; + guint n_segments; + guint segment_number, entry_size; guint64 time; GstClockTime stime; const guint8 *buffer; @@ -10861,7 +10981,7 @@ qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream, /*parse svmi header if existing */ svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi); if (svmi) { - guint len = QT_UINT32 ((guint8 *) svmi->data); + guint32 len = QT_UINT32 ((guint8 *) svmi->data); guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8); if (!version) { GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE; @@ -11268,7 +11388,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) break; } } else { - gint i, j, start, end; + guint i, j, start, end; if (len < 94) goto corrupt_file; @@ -11384,7 +11504,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (pasp) { const guint8 *pasp_data = (const guint8 *) pasp->data; - gint len = QT_UINT32 (pasp_data); + guint len = QT_UINT32 (pasp_data); if (len == 16) { CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8); @@ -11400,7 +11520,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (fiel) { const guint8 *fiel_data = (const guint8 *) fiel->data; - gint len = QT_UINT32 (fiel_data); + guint len = QT_UINT32 (fiel_data); if (len == 10) { CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8); @@ -11410,7 +11530,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (colr) { const guint8 *colr_data = (const guint8 *) colr->data; - gint len = QT_UINT32 (colr_data); + guint len = QT_UINT32 (colr_data); if (len == 19 || len == 18) { guint32 color_type = GST_READ_UINT32_LE (colr_data + 8); @@ -11447,14 +11567,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) case FOURCC_avc1: case FOURCC_avc3: { - gint len = QT_UINT32 (stsd_entry_data) - 0x56; + guint len = QT_UINT32 (stsd_entry_data); + len = len <= 0x56 ? 0 : len - 0x56; const guint8 *avc_data = stsd_entry_data + 0x56; /* find avcC */ while (len >= 0x8) { - gint size; + guint size; - if (QT_UINT32 (avc_data) <= len) + if (QT_UINT32 (avc_data) <= 0x8) + size = 0; + else if (QT_UINT32 (avc_data) <= len) size = QT_UINT32 (avc_data) - 0x8; else size = len - 0x8; @@ -11561,14 +11684,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) case FOURCC_dvh1: case FOURCC_dvhe: { - gint len = QT_UINT32 (stsd_entry_data) - 0x56; + guint len = QT_UINT32 (stsd_entry_data); + len = len <= 0x56 ? 0 : len - 0x56; const guint8 *hevc_data = stsd_entry_data + 0x56; /* find hevc */ while (len >= 0x8) { - gint size; + guint size; - if (QT_UINT32 (hevc_data) <= len) + if (QT_UINT32 (hevc_data) <= 0x8) + size = 0; + else if (QT_UINT32 (hevc_data) <= len) size = QT_UINT32 (hevc_data) - 0x8; else size = len - 0x8; @@ -11624,7 +11750,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (glbl) { guint8 *data; GstBuffer *buf; - gint len; + guint len; GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd"); data = glbl->data; @@ -11808,7 +11934,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) /* add codec_data if provided */ if (prefix) { GstBuffer *buf; - gint len; + guint len; GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd"); data = prefix->data; @@ -11830,7 +11956,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) GstBuffer *buf; GstBuffer *seqh = NULL; const guint8 *gamma_data = NULL; - gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */ + guint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */ qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data, &seqh); @@ -11982,14 +12108,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } case FOURCC_vc_1: { - gint len = QT_UINT32 (stsd_entry_data) - 0x56; + guint len = QT_UINT32 (stsd_entry_data); + len = len <= 0x56 ? 0 : len - 0x56; const guint8 *vc1_data = stsd_entry_data + 0x56; /* find dvc1 */ while (len >= 8) { - gint size; + guint size; - if (QT_UINT32 (vc1_data) <= len) + if (QT_UINT32 (vc1_data) <= 8) + size = 0; + else if (QT_UINT32 (vc1_data) <= len) size = QT_UINT32 (vc1_data) - 8; else size = len - 8; @@ -12021,14 +12150,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } case FOURCC_av01: { - gint len = QT_UINT32 (stsd_entry_data) - 0x56; + guint len = QT_UINT32 (stsd_entry_data); + len = len <= 0x56 ? 0 : len - 0x56; const guint8 *av1_data = stsd_entry_data + 0x56; /* find av1C */ while (len >= 0x8) { - gint size; + guint size; - if (QT_UINT32 (av1_data) <= len) + if (QT_UINT32 (av1_data) <= 0x8) + size = 0; + else if (QT_UINT32 (av1_data) <= len) size = QT_UINT32 (av1_data) - 0x8; else size = len - 0x8; @@ -12100,14 +12232,17 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) * vp08, vp09, and vp10 fourcc. */ case FOURCC_vp09: { - gint len = QT_UINT32 (stsd_entry_data) - 0x56; + guint len = QT_UINT32 (stsd_entry_data); + len = len <= 0x56 ? 0 : len - 0x56; const guint8 *vpcc_data = stsd_entry_data + 0x56; /* find vpcC */ while (len >= 0x8) { - gint size; + guint size; - if (QT_UINT32 (vpcc_data) <= len) + if (QT_UINT32 (vpcc_data) <= 0x8) + size = 0; + else if (QT_UINT32 (vpcc_data) <= len) size = QT_UINT32 (vpcc_data) - 0x8; else size = len - 0x8; @@ -12255,7 +12390,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } else if (stream->subtype == FOURCC_soun) { GNode *wave; - int version, samplesize; + guint version, samplesize; guint16 compression_id; gboolean amrwb = FALSE; @@ -12570,7 +12705,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } case FOURCC_wma_: { - gint len = QT_UINT32 (stsd_entry_data) - offset; + guint len = QT_UINT32 (stsd_entry_data); + len = len <= offset ? 0 : len - offset; const guint8 *wfex_data = stsd_entry_data + offset; const gchar *codec_name = NULL; gint version = 1; @@ -12594,9 +12730,11 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) /* find wfex */ while (len >= 8) { - gint size; + guint size; - if (QT_UINT32 (wfex_data) <= len) + if (QT_UINT32 (wfex_data) <= 0x8) + size = 0; + else if (QT_UINT32 (wfex_data) <= len) size = QT_UINT32 (wfex_data) - 8; else size = len - 8; @@ -13483,7 +13621,8 @@ qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux, /* unset new_stream to prevent stream-start event, unless we are EOS in which * case we need to force one through */ - newstream->new_stream = GST_PAD_IS_EOS (newstream->pad); + newstream->new_stream = newstream->pad != NULL + && GST_PAD_IS_EOS (newstream->pad); return gst_qtdemux_configure_stream (qtdemux, newstream); } @@ -13975,6 +14114,10 @@ qtdemux_parse_tree (GstQTDemux * qtdemux) /* parse any protection system info */ pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh); + if (pssh) { + /* Unref old protection events if we are going to receive new ones. */ + qtdemux_clear_protection_events_on_all_streams (qtdemux); + } while (pssh) { GST_LOG_OBJECT (qtdemux, "Parsing pssh box."); qtdemux_parse_pssh (qtdemux, pssh); @@ -14692,6 +14835,23 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, "stream-format", G_TYPE_STRING, "avc3", "alignment", G_TYPE_STRING, "au", NULL); break; + case FOURCC_ai12: + case FOURCC_ai13: + case FOURCC_ai15: + case FOURCC_ai16: + case FOURCC_ai1p: + case FOURCC_ai1q: + case FOURCC_ai52: + case FOURCC_ai53: + case FOURCC_ai55: + case FOURCC_ai56: + case FOURCC_ai5p: + case FOURCC_ai5q: + _codec ("H.264 / AVC"); + caps = gst_caps_new_simple ("video/x-h264", + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", NULL); + break; case FOURCC_H265: case FOURCC_hvc1: case FOURCC_dvh1: @@ -14858,6 +15018,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, case FOURCC_av01: _codec ("AV1"); caps = gst_caps_new_simple ("video/x-av1", + "stream-format", G_TYPE_STRING, "obu-stream", "alignment", G_TYPE_STRING, "tu", NULL); break; case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'): @@ -15344,8 +15505,8 @@ qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, || g_ascii_strcasecmp (content_encoding, "xml") == 0) { _codec ("ONVIF Timed XML MetaData"); caps = - gst_caps_new_simple ("application/x-onvif-metadata", "encoding", - G_TYPE_STRING, "utf8", NULL); + gst_caps_new_simple ("application/x-onvif-metadata", "parsed", + G_TYPE_BOOLEAN, TRUE, NULL); } else { GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s", content_encoding);