From a0bae2f656e1e42dc45b278eab86780589956d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 17 Dec 2007 20:31:35 +0000 Subject: [PATCH] ext/ffmpeg/: Add GIF (animations and single images) decoding and encoding support. Original commit message from CVS: * 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. --- ChangeLog | 12 ++++++++ common | 2 +- ext/ffmpeg/gstffmpegcodecmap.c | 34 ++++++++++++++++------- ext/ffmpeg/gstffmpegdemux.c | 50 ++++++++++++++++++++++++++++++---- ext/ffmpeg/gstffmpegmux.c | 35 ++++++++++++++++++++++-- 5 files changed, 115 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 82e20f3eec..0823514a9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2007-12-17 Sebastian Dröge + + * 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 * configure.ac: diff --git a/common b/common index a00d4c1966..208ef72f86 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit a00d4c1966aab517c2694c61d580489ebcbce448 +Subproject commit 208ef72f86e944e6ba6941c68e57ffcea8d2a8f4 diff --git a/ext/ffmpeg/gstffmpegcodecmap.c b/ext/ffmpeg/gstffmpegcodecmap.c index abb7832f0c..1a79acb7c4 100644 --- a/ext/ffmpeg/gstffmpegcodecmap.c +++ b/ext/ffmpeg/gstffmpegcodecmap.c @@ -636,8 +636,8 @@ gst_ffmpeg_codecid_to_caps (enum CodecID codec_id, 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); @@ -683,6 +683,10 @@ gst_ffmpeg_codecid_to_caps (enum CodecID codec_id, 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; @@ -1914,6 +1918,12 @@ gst_ffmpeg_formatid_get_codecids (const gchar * format_name, }; *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; @@ -2055,14 +2065,15 @@ gst_ffmpeg_caps_to_codecid (const GstCaps * caps, AVCodecContext * context) 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; } } @@ -2726,6 +2737,9 @@ gst_ffmpeg_get_codecid_longname (enum CodecID codec_id) case CODEC_ID_XVID: name = "XviD video"; break; + case CODEC_ID_GIF: + name = "GIF image"; + break; case CODEC_ID_PNG: name = "PNG image"; break; diff --git a/ext/ffmpeg/gstffmpegdemux.c b/ext/ffmpeg/gstffmpegdemux.c index 30872b7505..2bdac03ba1 100644 --- a/ext/ffmpeg/gstffmpegdemux.c +++ b/ext/ffmpeg/gstffmpegdemux.c @@ -1162,6 +1162,8 @@ gst_ffmpegdemux_loop (GstPad * pad) AVStream *avstream; GstBuffer *outbuf; GstClockTime timestamp, duration; + gint outsize; + gboolean rawvideo; demux = (GstFFMpegDemux *) (GST_PAD_PARENT (pad)); @@ -1222,16 +1224,52 @@ gst_ffmpegdemux_loop (GstPad * 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; @@ -1498,7 +1536,8 @@ gst_ffmpegdemux_register (GstPlugin * plugin) !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. @@ -1533,7 +1572,8 @@ gst_ffmpegdemux_register (GstPlugin * plugin) !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; diff --git a/ext/ffmpeg/gstffmpegmux.c b/ext/ffmpeg/gstffmpegmux.c index 3962d0ab01..3c0efdc061 100644 --- a/ext/ffmpeg/gstffmpegmux.c +++ b/ext/ffmpeg/gstffmpegmux.c @@ -525,6 +525,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data) if (best_pad != NULL) { GstBuffer *buf; AVPacket pkt; + gboolean need_free = FALSE; /* push out current buffer */ buf = gst_collect_pads_pop (ffmpegmux->collect, @@ -536,8 +537,30 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data) 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; @@ -552,6 +575,8 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data) 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); @@ -725,6 +750,12 @@ gst_ffmpegmux_register (GstPlugin * plugin) 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 */