+2007-12-17 Sebastian Dröge <slomo@circular-chaos.org>
+
+ * ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_codecid_to_caps),
+ (gst_ffmpeg_formatid_get_codecids),
+ (gst_ffmpeg_get_codecid_longname):
+ * ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_loop),
+ (gst_ffmpegdemux_register):
+ * ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_collected),
+ (gst_ffmpegmux_register):
+ Add GIF (animations and single images) decoding and encoding support.
+ Fixes #503249.
+
2007-12-17 Edward Hervey <edward.hervey@collabora.co.uk>
* configure.ac:
-Subproject commit a00d4c1966aab517c2694c61d580489ebcbce448
+Subproject commit 208ef72f86e944e6ba6941c68e57ffcea8d2a8f4
break;
case CODEC_ID_VC1:
caps = gst_ff_vid_caps_new (context, codec_id, "video/x-wmv",
- "wmvversion", G_TYPE_INT, 3, "fourcc", GST_TYPE_FOURCC,
- GST_MAKE_FOURCC('W', 'V', 'C', '1'), NULL);
+ "wmvversion", G_TYPE_INT, 3, "fourcc", GST_TYPE_FOURCC,
+ GST_MAKE_FOURCC ('W', 'V', 'C', '1'), NULL);
break;
case CODEC_ID_QDM2:
caps = gst_ff_aud_caps_new (context, codec_id, "audio/x-qdm2", NULL);
caps = gst_ff_vid_caps_new (context, codec_id, "video/x-nuv", NULL);
break;
+ case CODEC_ID_GIF:
+ caps = gst_ff_vid_caps_new (context, codec_id, "image/gif", NULL);
+ break;
+
case CODEC_ID_PNG:
caps = gst_ff_vid_caps_new (context, codec_id, "image/png", NULL);
break;
};
*video_codec_list = NULL;
*audio_codec_list = amr_audio_list;
+ } else if (!strcmp (format_name, "gif")) {
+ static enum CodecID gif_image_list[] = {
+ CODEC_ID_RAWVIDEO, CODEC_ID_NONE
+ };
+ *video_codec_list = gif_image_list;
+ *audio_codec_list = NULL;
} else {
GST_LOG ("Format %s not found", format_name);
return FALSE;
id = CODEC_ID_WMV2;
break;
case 3:
- {
- guint32 fourcc;
- if (gst_structure_get_fourcc (structure, "fourcc", &fourcc)) {
- if (fourcc == GST_MAKE_FOURCC ('W', 'V', 'C', '1'))
- id = CODEC_ID_VC1;
- } else
- id = CODEC_ID_WMV3;
- }
+ {
+ guint32 fourcc;
+
+ if (gst_structure_get_fourcc (structure, "fourcc", &fourcc)) {
+ if (fourcc == GST_MAKE_FOURCC ('W', 'V', 'C', '1'))
+ id = CODEC_ID_VC1;
+ } else
+ id = CODEC_ID_WMV3;
+ }
break;
}
}
case CODEC_ID_XVID:
name = "XviD video";
break;
+ case CODEC_ID_GIF:
+ name = "GIF image";
+ break;
case CODEC_ID_PNG:
name = "PNG image";
break;
AVStream *avstream;
GstBuffer *outbuf;
GstClockTime timestamp, duration;
+ gint outsize;
+ gboolean rawvideo;
demux = (GstFFMpegDemux *) (GST_PAD_PARENT (pad));
/* prepare to push packet to peer */
srcpad = stream->pad;
+ rawvideo = (avstream->codec->codec_type == CODEC_TYPE_VIDEO &&
+ avstream->codec->codec_id == CODEC_ID_RAWVIDEO);
+
+ if (rawvideo)
+ outsize = gst_ffmpeg_avpicture_get_size (avstream->codec->pix_fmt,
+ avstream->codec->width, avstream->codec->height);
+ else
+ outsize = pkt.size;
+
ret = gst_pad_alloc_buffer_and_set_caps (srcpad,
- GST_CLOCK_TIME_NONE, pkt.size, GST_PAD_CAPS (srcpad), &outbuf);
+ GST_CLOCK_TIME_NONE, outsize, GST_PAD_CAPS (srcpad), &outbuf);
/* we can ignore not linked */
if (ret == GST_FLOW_NOT_LINKED)
goto done;
if (ret != GST_FLOW_OK)
goto no_buffer;
- /* copy the data from packet into the target buffer */
- memcpy (GST_BUFFER_DATA (outbuf), pkt.data, pkt.size);
+ /* copy the data from packet into the target buffer
+ * and do conversions for raw video packets */
+ if (rawvideo) {
+ AVPicture src, dst;
+ const gchar *plugin_name =
+ ((GstFFMpegDemuxClass *) (G_OBJECT_GET_CLASS (demux)))->in_plugin->name;
+
+ if (strcmp (plugin_name, "gif") == 0) {
+ src.data[0] = pkt.data;
+ src.data[1] = NULL;
+ src.data[2] = NULL;
+ src.linesize[0] = avstream->codec->width * 3;;
+ } else {
+ GST_WARNING ("Unknown demuxer %s, no idea what to do", plugin_name);
+ gst_ffmpeg_avpicture_fill (&src, pkt.data,
+ avstream->codec->pix_fmt, avstream->codec->width,
+ avstream->codec->height);
+ }
+
+ gst_ffmpeg_avpicture_fill (&dst, GST_BUFFER_DATA (outbuf),
+ avstream->codec->pix_fmt, avstream->codec->width,
+ avstream->codec->height);
+
+ gst_ffmpeg_img_convert (&dst, avstream->codec->pix_fmt,
+ &src, avstream->codec->pix_fmt, avstream->codec->width,
+ avstream->codec->height);
+ } else {
+ memcpy (GST_BUFFER_DATA (outbuf), pkt.data, outsize);
+ }
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
GST_BUFFER_DURATION (outbuf) = duration;
!strcmp (in_plugin->name, "wav") ||
!strcmp (in_plugin->name, "au") ||
!strcmp (in_plugin->name, "tta") ||
- !strcmp (in_plugin->name, "rm") || !strcmp (in_plugin->name, "amr"))
+ !strcmp (in_plugin->name, "rm") ||
+ !strcmp (in_plugin->name, "amr") || !strcmp (in_plugin->name, "gif"))
register_typefind_func = FALSE;
/* Set the rank of demuxers know to work to MARGINAL.
!strcmp (in_plugin->name, "avs") ||
!strcmp (in_plugin->name, "aiff") ||
!strcmp (in_plugin->name, "4xm") ||
- !strcmp (in_plugin->name, "yuv4mpegpipe"))
+ !strcmp (in_plugin->name, "yuv4mpegpipe") ||
+ !strcmp (in_plugin->name, "gif"))
rank = GST_RANK_MARGINAL;
else
rank = GST_RANK_NONE;
if (best_pad != NULL) {
GstBuffer *buf;
AVPacket pkt;
+ gboolean need_free = FALSE;
/* push out current buffer */
buf = gst_collect_pads_pop (ffmpegmux->collect,
pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf),
ffmpegmux->context->streams[best_pad->padnum]->time_base);
pkt.dts = pkt.pts;
- pkt.data = GST_BUFFER_DATA (buf);
- pkt.size = GST_BUFFER_SIZE (buf);
+
+ if (strcmp (ffmpegmux->context->oformat->name, "gif") == 0) {
+ AVStream *st = ffmpegmux->context->streams[best_pad->padnum];
+ AVPicture src, dst;
+
+ need_free = TRUE;
+ pkt.size = st->codec->width * st->codec->height * 3;
+ pkt.data = g_malloc (pkt.size);
+
+ dst.data[0] = pkt.data;
+ dst.data[1] = NULL;
+ dst.data[2] = NULL;
+ dst.linesize[0] = st->codec->width * 3;
+
+ gst_ffmpeg_avpicture_fill (&src, GST_BUFFER_DATA (buf),
+ PIX_FMT_RGB24, st->codec->width, st->codec->height);
+
+ gst_ffmpeg_img_convert (&dst, PIX_FMT_RGB24,
+ &src, PIX_FMT_RGB24, st->codec->width, st->codec->height);
+ } else {
+ pkt.data = GST_BUFFER_DATA (buf);
+ pkt.size = GST_BUFFER_SIZE (buf);
+ }
+
pkt.stream_index = best_pad->padnum;
pkt.flags = 0;
pkt.duration = 0;
av_write_frame (ffmpegmux->context, &pkt);
gst_buffer_unref (buf);
+ if (need_free)
+ g_free (pkt.data);
} else {
/* close down */
av_write_trailer (ffmpegmux->context);
const gint rates[] = { 44100, 22050, 11025 };
gst_ffmpeg_mux_simple_caps_set_int_list (audiosinkcaps, "rate", 3, rates);
+ } else if (strcmp (in_plugin->name, "gif") == 0) {
+ if (videosinkcaps)
+ gst_caps_unref (videosinkcaps);
+
+ videosinkcaps =
+ gst_caps_from_string ("video/x-raw-rgb, bpp=(int)24, depth=(int)24");
}
/* create a cache for these properties */