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.
This commit is contained in:
Sebastian Dröge 2007-12-17 20:31:35 +00:00
parent f6186655c5
commit a0bae2f656
5 changed files with 115 additions and 18 deletions

View file

@ -1,3 +1,15 @@
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:

2
common

@ -1 +1 @@
Subproject commit a00d4c1966aab517c2694c61d580489ebcbce448
Subproject commit 208ef72f86e944e6ba6941c68e57ffcea8d2a8f4

View file

@ -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;

View file

@ -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;

View file

@ -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 */