[MOVED FROM BAD 21/57] gst/flv/: Introduce demuxing support for AAC and
authorJulien Moutte <julien@moutte.net>
Fri, 13 Jun 2008 22:46:43 +0000 (22:46 +0000)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 12 May 2009 19:20:54 +0000 (21:20 +0200)
Original commit message from CVS:
2008-06-14  Julien Moutte  <julien@fluendo.com>

* gst/flv/gstflvdemux.c: (gst_flv_demux_cleanup),
(gst_flv_demux_dispose):
* gst/flv/gstflvdemux.h:
* gst/flv/gstflvparse.c: (gst_flv_parse_audio_negotiate),
(gst_flv_parse_tag_audio), (gst_flv_parse_video_negotiate),
(gst_flv_parse_tag_video): Introduce demuxing support for AAC
and
H.264/AVC inside FLV.
* sys/dshowdecwrapper/gstdshowaudiodec.c:
(gst_dshowaudiodec_init),
(gst_dshowaudiodec_chain), (gst_dshowaudiodec_push_buffer),
(gst_dshowaudiodec_sink_event), (gst_dshowaudiodec_setup_graph):
* sys/dshowdecwrapper/gstdshowaudiodec.h:
* sys/dshowdecwrapper/gstdshowvideodec.c:
(gst_dshowvideodec_init),
(gst_dshowvideodec_sink_event), (gst_dshowvideodec_chain),
(gst_dshowvideodec_push_buffer),
(gst_dshowvideodec_src_getcaps):
* sys/dshowdecwrapper/gstdshowvideodec.h: Lot of random fixes
to improve stability (ref counting, safety checks...)

gst/flv/gstflvdemux.c
gst/flv/gstflvdemux.h
gst/flv/gstflvparse.c

index 045b3450fda7fb259e29861aa123da06bb33ad28..0f5e3f7978e1cba48fd0924264acca9958dfdb31 100644 (file)
@@ -118,6 +118,16 @@ gst_flv_demux_cleanup (GstFLVDemux * demux)
 
   gst_adapter_clear (demux->adapter);
 
+  if (demux->audio_codec_data) {
+    gst_buffer_unref (demux->audio_codec_data);
+    demux->audio_codec_data = NULL;
+  }
+
+  if (demux->video_codec_data) {
+    gst_buffer_unref (demux->video_codec_data);
+    demux->video_codec_data = NULL;
+  }
+
   if (demux->audio_pad) {
     gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
     gst_object_unref (demux->audio_pad);
@@ -1098,6 +1108,16 @@ gst_flv_demux_dispose (GObject * object)
     demux->new_seg_event = NULL;
   }
 
+  if (demux->audio_codec_data) {
+    gst_buffer_unref (demux->audio_codec_data);
+    demux->audio_codec_data = NULL;
+  }
+
+  if (demux->video_codec_data) {
+    gst_buffer_unref (demux->video_codec_data);
+    demux->video_codec_data = NULL;
+  }
+
   if (demux->audio_pad) {
     gst_object_unref (demux->audio_pad);
     demux->audio_pad = NULL;
index bd0832b0dc9b144d688574f3013b66da319c7f32..989584c414fa21962a33b5c3211786dc159f244c 100644 (file)
@@ -88,6 +88,7 @@ struct _GstFLVDemux
   gboolean audio_need_discont;
   gboolean audio_need_segment;
   gboolean audio_linked;
+  GstBuffer * audio_codec_data;
 
   /* Video infos */
   guint32 w;
@@ -100,6 +101,7 @@ struct _GstFLVDemux
   gboolean video_need_segment;
   gboolean video_linked;
   gboolean got_par;
+  GstBuffer * video_codec_data;
 
   gboolean random_access;
   gboolean need_header;
index 3a0e97b7ff0d31dc0413545eeae9843353e9287d..55a3ac67a729262804c2d94e1d1e4ea6034feeac 100644 (file)
@@ -391,6 +391,90 @@ gst_flv_parse_tag_script (GstFLVDemux * demux, const guint8 * data,
   return ret;
 }
 
+static gboolean
+gst_flv_parse_audio_negotiate (GstFLVDemux * demux, guint32 codec_tag,
+    guint32 rate, guint32 channels, guint32 width)
+{
+  GstCaps *caps = NULL;
+  gchar *codec_name = NULL;
+  gboolean ret = FALSE;
+
+  switch (codec_tag) {
+    case 1:
+      caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
+          "swf", NULL);
+      codec_name = "Shockwave ADPCM";
+      break;
+    case 2:
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
+      codec_name = "MPEG 1 Audio, Layer 3 (MP3)";
+      break;
+    case 0:
+    case 3:
+      caps = gst_caps_new_simple ("audio/x-raw-int",
+          "endianness", G_TYPE_INT, G_BYTE_ORDER,
+          "signed", G_TYPE_BOOLEAN, TRUE,
+          "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
+      codec_name = "Raw Audio";
+      break;
+    case 4:
+    case 5:
+    case 6:
+      caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
+      codec_name = "Nellymoser ASAO";
+      break;
+    case 10:
+      caps = gst_caps_new_simple ("audio/mpeg",
+          "mpegversion", G_TYPE_INT, 4, NULL);
+      codec_name = "AAC";
+      break;
+    default:
+      GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
+  }
+
+  if (G_UNLIKELY (!caps)) {
+    GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
+    goto beach;
+  }
+
+  gst_caps_set_simple (caps,
+      "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
+
+  if (demux->audio_codec_data) {
+    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
+        demux->audio_codec_data, NULL);
+  }
+
+  ret = gst_pad_set_caps (demux->audio_pad, caps);
+
+  if (G_LIKELY (ret)) {
+    /* Store the caps we have set */
+    demux->audio_codec_tag = codec_tag;
+    demux->rate = rate;
+    demux->channels = channels;
+    demux->width = width;
+
+    if (codec_name) {
+      if (demux->taglist == NULL)
+        demux->taglist = gst_tag_list_new ();
+      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+          GST_TAG_AUDIO_CODEC, codec_name, NULL);
+    }
+
+    GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
+        GST_PTR_FORMAT, caps);
+  } else {
+    GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
+        GST_PTR_FORMAT, caps);
+  }
+
+  gst_caps_unref (caps);
+
+beach:
+  return ret;
+}
+
 GstFlowReturn
 gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
     size_t data_size)
@@ -433,7 +517,11 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
   }
   /* Codec tag */
   codec_tag = flags >> 4;
-  codec_data = 1;
+  if (codec_tag == 10) {        /* AAC has an extra byte for packet type */
+    codec_data = 2;
+  } else {
+    codec_data = 1;
+  }
 
   GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
       "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
@@ -441,8 +529,6 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
 
   /* If we don't have our audio pad created, then create it. */
   if (G_UNLIKELY (!demux->audio_pad)) {
-    GstCaps *caps = NULL;
-    gchar *codec_name = NULL;
 
     demux->audio_pad = gst_pad_new ("audio", GST_PAD_SRC);
     if (G_UNLIKELY (!demux->audio_pad)) {
@@ -454,64 +540,17 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
     /* Make it active */
     gst_pad_set_active (demux->audio_pad, TRUE);
 
-    switch (codec_tag) {
-      case 1:
-        caps =
-            gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
-            "swf", NULL);
-        codec_name = "Shockwave ADPCM";
-        break;
-      case 2:
-        caps = gst_caps_new_simple ("audio/mpeg",
-            "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
-        codec_name = "MPEG 1 Audio, Layer 3 (MP3)";
-        break;
-      case 0:
-      case 3:
-        caps = gst_caps_new_simple ("audio/x-raw-int",
-            "endianness", G_TYPE_INT, G_BYTE_ORDER,
-            "signed", G_TYPE_BOOLEAN, TRUE,
-            "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
-        codec_name = "Raw Audio";
-        break;
-      case 5:
-      case 6:
-        caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
-        codec_name = "Nellymoser ASAO";
-        break;
-      default:
-        GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
-    }
-
-    if (G_UNLIKELY (!caps)) {
-      GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
-      ret = GST_FLOW_ERROR;
+    /* Negotiate caps */
+    if (!gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels,
+            width)) {
       gst_object_unref (demux->audio_pad);
       demux->audio_pad = NULL;
+      ret = GST_FLOW_ERROR;
       goto beach;
     }
 
-    gst_caps_set_simple (caps,
-        "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
-
-    gst_pad_set_caps (demux->audio_pad, caps);
-    if (codec_name) {
-      if (demux->taglist == NULL)
-        demux->taglist = gst_tag_list_new ();
-      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
-          GST_TAG_AUDIO_CODEC, codec_name, NULL);
-    }
-
     GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
-        caps);
-
-    gst_caps_unref (caps);
-
-    /* Store the caps we have set */
-    demux->audio_codec_tag = codec_tag;
-    demux->rate = rate;
-    demux->channels = channels;
-    demux->width = width;
+        GST_PAD_CAPS (demux->audio_pad));
 
     /* Set functions on the pad */
     gst_pad_set_query_type_function (demux->audio_pad,
@@ -537,61 +576,10 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
   /* Check if caps have changed */
   if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
           codec_tag != demux->audio_codec_tag || width != demux->width)) {
-    GstCaps *caps = NULL;
-    gchar *codec_name = NULL;
-
     GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
 
-    switch (codec_tag) {
-      case 1:
-        caps =
-            gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
-            "swf", NULL);
-        codec_name = "Shockwave ADPCM";
-        break;
-      case 2:
-        caps = gst_caps_new_simple ("audio/mpeg",
-            "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL);
-        codec_name = "MPEG 1 Audio, Layer 3 (MP3)";
-        break;
-      case 0:
-      case 3:
-        caps = gst_caps_new_simple ("audio/x-raw-int", NULL);
-        codec_name = "Raw Audio";
-        break;
-      case 6:
-        caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
-        codec_name = "Nellymoser ASAO";
-        break;
-      default:
-        GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
-    }
-
-    if (G_UNLIKELY (!caps)) {
-      GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
-      ret = GST_FLOW_ERROR;
-      goto beach;
-    }
-
-    gst_caps_set_simple (caps,
-        "rate", G_TYPE_INT, rate,
-        "channels", G_TYPE_INT, channels, "width", G_TYPE_INT, width, NULL);
-
-    gst_pad_set_caps (demux->audio_pad, caps);
-    if (codec_name) {
-      if (demux->taglist == NULL)
-        demux->taglist = gst_tag_list_new ();
-      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
-          GST_TAG_AUDIO_CODEC, codec_name, NULL);
-    }
-
-    gst_caps_unref (caps);
-
-    /* Store the caps we have set */
-    demux->audio_codec_tag = codec_tag;
-    demux->rate = rate;
-    demux->channels = channels;
-    demux->width = width;
+    /* Negotiate caps */
+    gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, width);
   }
 
   /* Push taglist if present */
@@ -627,8 +615,38 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
     goto beach;
   }
 
+  memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data,
+      MIN (demux->tag_data_size - codec_data, GST_BUFFER_SIZE (buffer)));
+
   demux->audio_linked = TRUE;
 
+  if (demux->audio_codec_tag == 10) {
+    guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
+
+    switch (aac_packet_type) {
+      case 0:
+      {
+        /* AudioSpecificConfic 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 = buffer;
+        /* Use that buffer data in the caps */
+        gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, width);
+        goto beach;
+        break;
+      }
+      case 1:
+        /* 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);
+    }
+  }
+
   /* Fill buffer with data */
   GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND;
   GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
@@ -663,9 +681,6 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data,
     demux->audio_need_segment = FALSE;
   }
 
-  memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data,
-      demux->tag_data_size - codec_data);
-
   GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
       GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
@@ -678,6 +693,74 @@ beach:
   return ret;
 }
 
+static gboolean
+gst_flv_parse_video_negotiate (GstFLVDemux * demux, guint32 codec_tag)
+{
+  gboolean ret = FALSE;
+  GstCaps *caps = NULL;
+  gchar *codec_name = NULL;
+
+  /* Generate caps for that pad */
+  switch (codec_tag) {
+    case 2:
+      caps = gst_caps_new_simple ("video/x-flash-video", NULL);
+      codec_name = "Sorenson Video";
+      break;
+    case 3:
+      caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
+      codec_name = "Flash Screen Video";
+    case 4:
+    case 5:
+      caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
+      codec_name = "On2 VP6 Video";
+      break;
+    case 7:
+      caps = gst_caps_new_simple ("video/x-h264", NULL);
+      codec_name = "H.264/AVC Video";
+      break;
+    default:
+      GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
+  }
+
+  if (G_UNLIKELY (!caps)) {
+    GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
+    goto beach;
+  }
+
+  gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+      demux->par_x, demux->par_y, NULL);
+
+  if (demux->video_codec_data) {
+    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
+        demux->video_codec_data, NULL);
+  }
+
+  ret = gst_pad_set_caps (demux->video_pad, caps);
+
+  if (G_LIKELY (ret)) {
+    /* Store the caps we have set */
+    demux->video_codec_tag = codec_tag;
+
+    if (codec_name) {
+      if (demux->taglist == NULL)
+        demux->taglist = gst_tag_list_new ();
+      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
+          GST_TAG_VIDEO_CODEC, codec_name, NULL);
+    }
+
+    GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
+        GST_PTR_FORMAT, caps);
+  } else {
+    GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
+        GST_PTR_FORMAT, caps);
+  }
+
+  gst_caps_unref (caps);
+
+beach:
+  return ret;
+}
+
 GstFlowReturn
 gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
     size_t data_size)
@@ -710,6 +793,8 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
   codec_tag = flags & 0x0F;
   if (codec_tag == 4 || codec_tag == 5) {
     codec_data = 2;
+  } else if (codec_tag == 7) {
+    codec_data = 5;
   }
 
   GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
@@ -717,9 +802,6 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
 
   /* If we don't have our video pad created, then create it. */
   if (G_UNLIKELY (!demux->video_pad)) {
-    GstCaps *caps = NULL;
-    gchar *codec_name = NULL;
-
     demux->video_pad = gst_pad_new ("video", GST_PAD_SRC);
     if (G_UNLIKELY (!demux->video_pad)) {
       GST_WARNING_OBJECT (demux, "failed creating video pad");
@@ -729,54 +811,19 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
     /* Make it active */
     gst_pad_set_active (demux->video_pad, TRUE);
 
-    /* Generate caps for that pad */
-    switch (codec_tag) {
-      case 2:
-        caps = gst_caps_new_simple ("video/x-flash-video", NULL);
-        codec_name = "Sorenson Video";
-        break;
-      case 3:
-        caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
-        codec_name = "Flash Screen Video";
-      case 4:
-      case 5:
-        caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
-        codec_name = "On2 VP6 Video";
-        break;
-      default:
-        GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag);
-    }
-
-    if (G_UNLIKELY (!caps)) {
-      GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
+    if (!gst_flv_parse_video_negotiate (demux, codec_tag)) {
       gst_object_unref (demux->video_pad);
       demux->video_pad = NULL;
       ret = GST_FLOW_ERROR;
       goto beach;
     }
 
-    gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
-        demux->par_x, demux->par_y, NULL);
-
     /* When we ve set pixel-aspect-ratio we use that boolean to detect a 
      * metadata tag that would come later and trigger a caps change */
     demux->got_par = FALSE;
 
-    gst_pad_set_caps (demux->video_pad, caps);
-
     GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
-        caps);
-
-    gst_caps_unref (caps);
-    if (codec_name) {
-      if (demux->taglist == NULL)
-        demux->taglist = gst_tag_list_new ();
-      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
-          GST_TAG_VIDEO_CODEC, codec_name, NULL);
-    }
-
-    /* Store the caps we have set */
-    demux->video_codec_tag = codec_tag;
+        GST_PAD_CAPS (demux->video_pad));
 
     /* Set functions on the pad */
     gst_pad_set_query_type_function (demux->video_pad,
@@ -801,54 +848,14 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
 
   /* Check if caps have changed */
   if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
-    GstCaps *caps = NULL;
-    gchar *codec_name = NULL;
 
     GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
 
-    /* Generate caps for that pad */
-    switch (codec_tag) {
-      case 2:
-        caps = gst_caps_new_simple ("video/x-flash-video", NULL);
-        codec_name = "Sorenson Video";
-        break;
-      case 3:
-        caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
-        codec_name = "Flash Screen Video";
-      case 4:
-      case 5:
-        caps = gst_caps_new_simple ("video/x-vp6", NULL);
-        codec_name = "On2 VP6 Video";
-        break;
-      default:
-        GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag);
-    }
-
-    if (G_UNLIKELY (!caps)) {
-      GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
-      ret = GST_FLOW_ERROR;
-      goto beach;
-    }
-
-    gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
-        demux->par_x, demux->par_y, NULL);
+    gst_flv_parse_video_negotiate (demux, codec_tag);
 
     /* When we ve set pixel-aspect-ratio we use that boolean to detect a 
      * metadata tag that would come later and trigger a caps change */
     demux->got_par = FALSE;
-
-    gst_pad_set_caps (demux->video_pad, caps);
-
-    gst_caps_unref (caps);
-    if (codec_name) {
-      if (demux->taglist == NULL)
-        demux->taglist = gst_tag_list_new ();
-      gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
-          GST_TAG_VIDEO_CODEC, codec_name, NULL);
-    }
-
-    /* Store the caps we have set */
-    demux->video_codec_tag = codec_tag;
   }
 
   /* Push taglist if present */
@@ -886,6 +893,36 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
 
   demux->video_linked = TRUE;
 
+  memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data,
+      MIN (demux->tag_data_size - codec_data, GST_BUFFER_SIZE (buffer)));
+
+  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 = buffer;
+        /* Use that buffer data in the caps */
+        gst_flv_parse_video_negotiate (demux, codec_tag);
+        goto beach;
+        break;
+      }
+      case 1:
+        /* H.264 NALU packet */
+        GST_LOG_OBJECT (demux, "got a H.264 NALU audio packet");
+        break;
+      default:
+        GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
+            avc_packet_type);
+    }
+  }
+
   /* Fill buffer with data */
   GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND;
   GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
@@ -934,10 +971,6 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data,
     demux->video_need_segment = FALSE;
   }
 
-  /* FIXME: safety checks */
-  memcpy (GST_BUFFER_DATA (buffer), data + 7 + codec_data,
-      demux->tag_data_size - codec_data);
-
   GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
       ", keyframe (%d)", GST_BUFFER_SIZE (buffer),