#include "gstflvmux.h"
#include <string.h>
+#include <stdio.h>
#include <gst/base/gstbytereader.h>
#include <gst/base/gstbytewriter.h>
#include <gst/pbutils/descriptions.h>
#include <gst/pbutils/pbutils.h>
#include <gst/audio/audio.h>
#include <gst/video/video.h>
+#include <gst/tag/tag.h>
/* FIXME: don't rely on own GstIndex */
#include "gstindex.c"
"audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
"audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
"audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
- "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
- "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
+ "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) 8000; "
+ "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) 8000; "
"audio/x-speex, channels = (int) 1, rate = (int) 16000;")
);
static GstIndex *gst_flv_demux_get_index (GstElement * element);
+static void gst_flv_demux_push_tags (GstFlvDemux * demux);
+
static void
gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
guint64 pos, gboolean keyframe)
GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
}
-static void
-parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
+static GstDateTime *
+parse_flv_demux_parse_date_string (const gchar * s)
{
- g_date_set_parse (date, s);
- if (g_date_valid (date))
- return;
+ static const gchar months[12][4] = {
+ "Jan", "Feb", "Mar", "Apr",
+ "May", "Jun", "Jul", "Aug",
+ "Sep", "Oct", "Nov", "Dec"
+ };
+ GstDateTime *dt = NULL;
+ gchar **tokens;
+ guint64 d;
+ gchar *endptr, *stripped;
+ gint i, hh, mm, ss;
+ gint year = -1, month = -1, day = -1;
+ gint hour = -1, minute = -1, seconds = -1;
+
+ stripped = g_strstrip (g_strdup (s));
/* "Fri Oct 15 15:13:16 2004" needs to be parsed */
- {
- static const gchar *months[] = {
- "Jan", "Feb", "Mar", "Apr",
- "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec"
- };
- gchar **tokens = g_strsplit (s, " ", -1);
- guint64 d;
- gchar *endptr;
- gint i;
-
- if (g_strv_length (tokens) != 5)
- goto out;
-
- if (strlen (tokens[1]) != 3)
- goto out;
- for (i = 0; i < 12; i++) {
- if (!strcmp (tokens[1], months[i])) {
- break;
- }
- }
- if (i == 12)
- goto out;
- g_date_set_month (date, i + 1);
+ tokens = g_strsplit (stripped, " ", -1);
- d = g_ascii_strtoull (tokens[2], &endptr, 10);
- if (d == 0 && *endptr != '\0')
- goto out;
+ g_free (stripped);
+
+ if (g_strv_length (tokens) != 5)
+ goto out;
+
+ /* year */
+ d = g_ascii_strtoull (tokens[4], &endptr, 10);
+ if (d == 0 && *endptr != '\0')
+ goto out;
+
+ year = d;
+
+ /* month */
+ if (strlen (tokens[1]) != 3)
+ goto out;
+ for (i = 0; i < 12; i++) {
+ if (!strcmp (tokens[1], months[i])) {
+ break;
+ }
+ }
+ if (i == 12)
+ goto out;
- g_date_set_day (date, d);
+ month = i + 1;
- d = g_ascii_strtoull (tokens[4], &endptr, 10);
- if (d == 0 && *endptr != '\0')
- goto out;
+ /* day */
+ d = g_ascii_strtoull (tokens[2], &endptr, 10);
+ if (d == 0 && *endptr != '\0')
+ goto out;
- g_date_set_year (date, d);
+ day = d;
- out:
- if (tokens)
- g_strfreev (tokens);
+ /* time */
+ hh = mm = ss = 0;
+ if (sscanf (tokens[3], "%d:%d:%d", &hh, &mm, &ss) < 2)
+ goto out;
+ if (hh >= 0 && hh < 24 && mm >= 0 && mm < 60 && ss >= 0 && ss < 60) {
+ hour = hh;
+ minute = mm;
+ seconds = ss;
}
+
+out:
+
+ if (tokens)
+ g_strfreev (tokens);
+
+ if (year > 0)
+ dt = gst_date_time_new (0.0, year, month, day, hour, minute, seconds);
+
+ return dt;
}
static gboolean
demux->h = d;
} else if (!strcmp (tag_name, "framerate")) {
demux->framerate = d;
+ } else if (!strcmp (tag_name, "audiodatarate")) {
+ gst_tag_list_add (demux->audio_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL);
+ } else if (!strcmp (tag_name, "videodatarate")) {
+ gst_tag_list_add (demux->video_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL);
} else {
GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
}
GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
if (!strcmp (tag_name, "creationdate")) {
- GDate *date = g_date_new ();
+ GstDateTime *dt;
- parse_flv_demux_parse_date_string (date, s);
- if (!g_date_valid (date)) {
- GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
+ dt = parse_flv_demux_parse_date_string (s);
+ if (dt == NULL) {
+ GST_DEBUG_OBJECT (demux, "Failed to parse '%s' into datetime", s);
} else {
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_DATE, date, NULL);
+ GST_TAG_DATE_TIME, dt, NULL);
+ gst_date_time_unref (dt);
}
- g_date_free (date);
} else if (!strcmp (tag_name, "creator")) {
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
GST_TAG_ARTIST, s, NULL);
} else if (!strcmp (tag_name, "title")) {
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
GST_TAG_TITLE, s, NULL);
- } else if (!strcmp (tag_name, "metadatacreator")) {
+ } else if (!strcmp (tag_name, "metadatacreator")
+ || !strcmp (tag_name, "encoder")) {
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
GST_TAG_ENCODER, s, NULL);
} else {
return FALSE;
}
+static void
+gst_flv_demux_clear_tags (GstFlvDemux * demux)
+{
+ GST_DEBUG_OBJECT (demux, "clearing taglist");
+
+ if (demux->taglist) {
+ gst_tag_list_unref (demux->taglist);
+ }
+ demux->taglist = gst_tag_list_new_empty ();
+ gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
+
+ if (demux->audio_tags) {
+ gst_tag_list_unref (demux->audio_tags);
+ }
+ demux->audio_tags = gst_tag_list_new_empty ();
+
+ if (demux->video_tags) {
+ gst_tag_list_unref (demux->video_tags);
+ }
+ demux->video_tags = gst_tag_list_new_empty ();
+}
+
static GstFlowReturn
gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
{
gboolean end_marker = FALSE;
GST_DEBUG_OBJECT (demux, "we have a metadata script object");
+ gst_flv_demux_clear_tags (demux);
+
if (!gst_byte_reader_get_uint8 (&reader, &type)) {
g_free (function_name);
goto cleanup;
goto cleanup;
}
- demux->push_tags = TRUE;
+ gst_flv_demux_push_tags (demux);
}
g_free (function_name);
guint32 rate, guint32 channels, guint32 width)
{
GstCaps *caps = NULL, *old_caps;
- gchar *codec_name = NULL;
gboolean ret = FALSE;
guint adjusted_rate = rate;
+ guint adjusted_channels = channels;
GstEvent *event;
gchar *stream_id;
} else {
adjusted_rate = rate;
}
+
+ adjusted_channels =
+ gst_codec_utils_aac_get_channels (map.data, map.size);
+
+ if (adjusted_channels && (channels != adjusted_channels)) {
+ GST_LOG_OBJECT (demux, "Ajusting AAC channels %d -> %d", channels,
+ adjusted_channels);
+ } else {
+ adjusted_channels = channels;
+ }
}
gst_buffer_unmap (demux->audio_codec_data, &map);
GstByteWriter w;
GstStructure *structure;
GstBuffer *buf;
+ GstTagList *tags;
caps = gst_caps_new_empty_simple ("audio/x-speex");
structure = gst_caps_get_structure (caps, 0);
/* comment part */
g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_new_wrapped (g_memdup ("No comments", 12), 12);
+ tags = gst_tag_list_new_empty ();
+ buf = gst_tag_list_to_vorbiscomment_buffer (tags, NULL, 0, "No comments");
+ gst_tag_list_unref (tags);
g_value_take_boxed (&value, buf);
gst_value_array_append_value (&streamheader, &value);
g_value_unset (&value);
}
gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
- "channels", G_TYPE_INT, channels, NULL);
+ "channels", G_TYPE_INT, adjusted_channels, NULL);
if (demux->audio_codec_data) {
gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
demux->width = width;
if (caps) {
- codec_name = gst_pb_utils_get_codec_description (caps);
-
- if (codec_name) {
- if (demux->taglist == NULL)
- demux->taglist = gst_tag_list_new_empty ();
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_AUDIO_CODEC, codec_name, NULL);
-#ifdef TIZEN_FEATURE_FLVDEMUX_MODIFICATION
- GST_DEBUG_OBJECT (demux, "post tag msg %" GST_PTR_FORMAT,
- demux->taglist);
-
- /* post message flv tag (for early recive application) */
- gst_element_post_message (GST_ELEMENT_CAST (demux),
- gst_message_new_tag (GST_OBJECT_CAST (demux),
- gst_tag_list_copy (demux->taglist)));
-#endif
- g_free (codec_name);
- }
-
GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
GST_PTR_FORMAT, caps);
+
+ gst_flv_demux_push_tags (demux);
} else {
GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
}
}
static void
-gst_flv_demux_push_tags (GstFlvDemux * demux)
+gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
+ GstPad * pad)
{
- if (demux->has_audio && !demux->audio_pad) {
- GST_DEBUG_OBJECT (demux,
- "Waiting for audio stream pad to come up before we can push tags");
- return;
+ if (pad) {
+ GstCaps *caps = gst_pad_get_current_caps (pad);
+
+ if (caps) {
+ gchar *codec_name = gst_pb_utils_get_codec_description (caps);
+
+ if (codec_name) {
+ gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+ tag, codec_name, NULL);
+ g_free (codec_name);
+ }
+
+ gst_caps_unref (caps);
+ }
}
- if (demux->has_video && !demux->video_pad) {
- GST_DEBUG_OBJECT (demux,
- "Waiting for video stream pad to come up before we can push tags");
- return;
+}
+
+static void
+gst_flv_demux_push_tags (GstFlvDemux * demux)
+{
+ gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
+ gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
+
+ GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
+
+ gst_flv_demux_push_src_event (demux,
+ gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
+
+#ifdef TIZEN_FEATURE_FLVDEMUX_MODIFICATION
+ GST_DEBUG_OBJECT (demux, "post tag msg %" GST_PTR_FORMAT, demux->taglist);
+
+ /* post message flv tag (for early recive application) */
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_tag (GST_OBJECT_CAST (demux),
+ gst_tag_list_copy (demux->taglist)));
+#endif
+
+ if (demux->audio_pad) {
+ GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
+ demux->audio_tags);
+ gst_pad_push_event (demux->audio_pad,
+ gst_event_new_tag (gst_tag_list_copy (demux->audio_tags)));
}
- if (demux->taglist) {
- GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
- demux->taglist);
- gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
- gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
- demux->taglist = gst_tag_list_new_empty ();
- demux->push_tags = FALSE;
+
+ if (demux->video_pad) {
+ GST_DEBUG_OBJECT (demux->video_pad, "pushing video %" GST_PTR_FORMAT,
+ demux->video_tags);
+ gst_pad_push_event (demux->video_pad,
+ gst_event_new_tag (gst_tag_list_copy (demux->video_tags)));
}
}
}
/* codec tags with special rates */
- if (codec_tag == 5 || codec_tag == 14)
+ if (codec_tag == 5 || codec_tag == 14 || codec_tag == 7 || codec_tag == 8)
rate = 8000;
- else if (codec_tag == 4)
+ else if ((codec_tag == 4) || (codec_tag == 11))
rate = 16000;
GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
"%d bits width, codec tag %u (flags %02X)", channels, rate, width,
codec_tag, flags);
+ if (codec_tag == 10) {
+ guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
+
+ switch (aac_packet_type) {
+ case 0:
+ {
+ /* AudioSpecificConfig data */
+ GST_LOG_OBJECT (demux, "got an AAC codec data packet");
+ if (demux->audio_codec_data) {
+ gst_buffer_unref (demux->audio_codec_data);
+ }
+ demux->audio_codec_data =
+ gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
+ 7 + codec_data, demux->tag_data_size - codec_data);
+
+ /* Use that buffer data in the caps */
+ if (demux->audio_pad)
+ gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
+ width);
+ goto beach;
+ }
+ case 1:
+ if (!demux->audio_codec_data) {
+ GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
+ ret = GST_FLOW_OK;
+ goto beach;
+ }
+ /* AAC raw packet */
+ GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
+ break;
+ default:
+ GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
+ aac_packet_type);
+ }
+ }
+
/* If we don't have our audio pad created, then create it. */
if (G_UNLIKELY (!demux->audio_pad)) {
-
demux->audio_pad =
gst_pad_new_from_template (gst_element_class_get_pad_template
(GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
GST_DEBUG_OBJECT (demux, "emitting no more pads");
gst_element_no_more_pads (GST_ELEMENT (demux));
demux->no_more_pads = TRUE;
- demux->push_tags = TRUE;
}
}
}
}
- /* Push taglist if present */
- if (G_UNLIKELY (demux->push_tags))
- gst_flv_demux_push_tags (demux);
-
/* Check if we have anything to push */
if (demux->tag_data_size <= codec_data) {
GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
7 + codec_data, demux->tag_data_size - codec_data);
- if (demux->audio_codec_tag == 10) {
- guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
-
- switch (aac_packet_type) {
- case 0:
- {
- /* AudioSpecificConfig data */
- GST_LOG_OBJECT (demux, "got an AAC codec data packet");
- if (demux->audio_codec_data) {
- gst_buffer_unref (demux->audio_codec_data);
- }
- demux->audio_codec_data = outbuf;
- /* Use that buffer data in the caps */
- gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
- goto beach;
- }
- case 1:
- if (!demux->audio_codec_data) {
- GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
- ret = GST_FLOW_OK;
- gst_buffer_unref (outbuf);
- goto beach;
- }
- /* AAC raw packet */
- GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
- break;
- default:
- GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
- aac_packet_type);
- }
- }
-
/* detect (and deem to be resyncs) large pts gaps */
if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
&demux->last_audio_pts, &demux->audio_time_offset)) {
" after 6 seconds of audio");
gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
demux->no_more_pads = TRUE;
- demux->push_tags = TRUE;
}
/* Push downstream */
{
gboolean ret = FALSE;
GstCaps *caps = NULL, *old_caps;
- gchar *codec_name = NULL;
GstEvent *event;
gchar *stream_id;
gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
"avc", NULL);
break;
+ /* The following two are non-standard but apparently used, see in ffmpeg
+ * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l254
+ * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l282
+ */
+ case 8:
+ caps = gst_caps_new_empty_simple ("video/x-h263");
+ break;
+ case 9:
+ caps =
+ gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ break;
default:
GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
}
goto beach;
}
- gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- demux->par_x, demux->par_y, NULL);
+ if (demux->got_par) {
+ gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ demux->par_x, demux->par_y, NULL);
+ }
if (G_LIKELY (demux->w)) {
gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
demux->video_codec_tag = codec_tag;
if (caps) {
- codec_name = gst_pb_utils_get_codec_description (caps);
-
- if (codec_name) {
- if (demux->taglist == NULL)
- demux->taglist = gst_tag_list_new_empty ();
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_VIDEO_CODEC, codec_name, NULL);
- g_free (codec_name);
- }
-
GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
GST_PTR_FORMAT, caps);
+
+ gst_flv_demux_push_tags (demux);
} else {
GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
}
cts = GST_READ_UINT24_BE (data + 9);
cts = (cts + 0xff800000) ^ 0xff800000;
+ if (cts < 0 && ABS (cts) > dts) {
+ GST_ERROR_OBJECT (demux, "Detected a negative composition time offset "
+ "'%d' that would lead to negative PTS, fixing", cts);
+ cts += ABS (cts) - dts;
+ }
+
GST_LOG_OBJECT (demux, "got cts %d", cts);
}
GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
"(flags %02X)", codec_tag, keyframe, flags);
+ if (codec_tag == 7) {
+ guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
+
+ switch (avc_packet_type) {
+ case 0:
+ {
+ if (demux->tag_data_size < codec_data) {
+ GST_ERROR_OBJECT (demux, "Got invalid H.264 codec, ignoring.");
+ break;
+ }
+
+ /* AVCDecoderConfigurationRecord data */
+ GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
+ if (demux->video_codec_data) {
+ gst_buffer_unref (demux->video_codec_data);
+ }
+ demux->video_codec_data = gst_buffer_copy_region (buffer,
+ GST_BUFFER_COPY_MEMORY, 7 + codec_data,
+ demux->tag_data_size - codec_data);;
+ /* Use that buffer data in the caps */
+ if (demux->video_pad)
+ gst_flv_demux_video_negotiate (demux, codec_tag);
+ goto beach;
+ }
+ case 1:
+ /* H.264 NALU packet */
+ if (!demux->video_codec_data) {
+ GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
+ ret = GST_FLOW_OK;
+ goto beach;
+ }
+ GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
+ break;
+ default:
+ GST_WARNING_OBJECT (demux, "invalid video packet type %u",
+ avc_packet_type);
+ }
+ }
+
/* If we don't have our video pad created, then create it. */
if (G_UNLIKELY (!demux->video_pad)) {
demux->video_pad =
GST_DEBUG_OBJECT (demux, "emitting no more pads");
gst_element_no_more_pads (GST_ELEMENT (demux));
demux->no_more_pads = TRUE;
- demux->push_tags = TRUE;
}
}
demux->got_par = FALSE;
}
- /* Push taglist if present */
- if (G_UNLIKELY (demux->push_tags))
- gst_flv_demux_push_tags (demux);
-
/* Check if we have anything to push */
if (demux->tag_data_size <= codec_data) {
GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
7 + codec_data, demux->tag_data_size - codec_data);
- if (demux->video_codec_tag == 7) {
- guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
-
- switch (avc_packet_type) {
- case 0:
- {
- /* AVCDecoderConfigurationRecord data */
- GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
- if (demux->video_codec_data) {
- gst_buffer_unref (demux->video_codec_data);
- }
- demux->video_codec_data = outbuf;
- /* Use that buffer data in the caps */
- gst_flv_demux_video_negotiate (demux, codec_tag);
- goto beach;
- }
- case 1:
- /* H.264 NALU packet */
- if (!demux->video_codec_data) {
- GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
- ret = GST_FLOW_OK;
- gst_buffer_unref (outbuf);
- goto beach;
- }
- GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
- break;
- default:
- GST_WARNING_OBJECT (demux, "invalid video packet type %u",
- avc_packet_type);
- }
- }
-
/* detect (and deem to be resyncs) large dts gaps */
if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
&demux->last_video_dts, &demux->video_time_offset)) {
" after 6 seconds of video");
gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
demux->no_more_pads = TRUE;
- demux->push_tags = TRUE;
}
/* Push downstream */
demux->has_audio = FALSE;
demux->has_video = FALSE;
- demux->push_tags = FALSE;
demux->got_par = FALSE;
demux->indexed = FALSE;
g_array_free (demux->filepositions, TRUE);
demux->filepositions = NULL;
}
+
+ gst_flv_demux_clear_tags (demux);
}
/*
gst_buffer_unref (buffer);
buffer = NULL;
+ if (G_UNLIKELY (offset < tag_size))
+ goto exit;
+
offset -= tag_size;
if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
12, &buffer))
}
/* pause if something went wrong or at end */
- if (G_UNLIKELY (ret != GST_FLOW_OK))
+ if (G_UNLIKELY (ret != GST_FLOW_OK) && !(ret == GST_FLOW_NOT_LINKED
+ && !demux->no_more_pads))
goto pause;
gst_object_unref (demux);
GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
}
} else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
- GST_ELEMENT_ERROR (demux, STREAM, FAILED,
- ("Internal data stream error."),
- ("stream stopped, reason %s", reason));
+ GST_ELEMENT_FLOW_ERROR (demux, ret);
gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
}
gst_object_unref (demux);
gst_object_unref (index);
}
- if (!demux->audio_pad && !demux->video_pad)
+ if (!demux->audio_pad && !demux->video_pad) {
GST_ELEMENT_ERROR (demux, STREAM, FAILED,
("Internal data stream error."), ("Got EOS before any data"));
- else {
+ gst_event_unref (event);
+ } else {
if (!demux->no_more_pads) {
gst_element_no_more_pads (GST_ELEMENT (demux));
demux->no_more_pads = TRUE;
demux->taglist = NULL;
}
+ if (demux->audio_tags) {
+ gst_tag_list_unref (demux->audio_tags);
+ demux->audio_tags = NULL;
+ }
+
+ if (demux->video_tags) {
+ gst_tag_list_unref (demux->video_tags);
+ demux->video_tags = NULL;
+ }
+
if (demux->flowcombiner) {
gst_flow_combiner_free (demux->flowcombiner);
demux->flowcombiner = NULL;
gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
#endif
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&flv_sink_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&audio_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&video_src_template));
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &flv_sink_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &audio_src_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &video_src_template);
gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
- "Codec/Demuxer",
- "Demux FLV feeds into digital streams",
+ "Codec/Demuxer", "Demux FLV feeds into digital streams",
"Julien Moutte <julien@moutte.net>");
}
gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
demux->adapter = gst_adapter_new ();
- demux->taglist = gst_tag_list_new_empty ();
demux->flowcombiner = gst_flow_combiner_new ();
- gst_segment_init (&demux->segment, GST_FORMAT_TIME);
demux->own_index = FALSE;