mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-06 10:42:22 +00:00
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:
parent
f6186655c5
commit
a0bae2f656
5 changed files with 115 additions and 18 deletions
12
ChangeLog
12
ChangeLog
|
@ -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>
|
2007-12-17 Edward Hervey <edward.hervey@collabora.co.uk>
|
||||||
|
|
||||||
* configure.ac:
|
* configure.ac:
|
||||||
|
|
2
common
2
common
|
@ -1 +1 @@
|
||||||
Subproject commit a00d4c1966aab517c2694c61d580489ebcbce448
|
Subproject commit 208ef72f86e944e6ba6941c68e57ffcea8d2a8f4
|
|
@ -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);
|
caps = gst_ff_vid_caps_new (context, codec_id, "video/x-nuv", NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CODEC_ID_GIF:
|
||||||
|
caps = gst_ff_vid_caps_new (context, codec_id, "image/gif", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
case CODEC_ID_PNG:
|
case CODEC_ID_PNG:
|
||||||
caps = gst_ff_vid_caps_new (context, codec_id, "image/png", NULL);
|
caps = gst_ff_vid_caps_new (context, codec_id, "image/png", NULL);
|
||||||
break;
|
break;
|
||||||
|
@ -1914,6 +1918,12 @@ gst_ffmpeg_formatid_get_codecids (const gchar * format_name,
|
||||||
};
|
};
|
||||||
*video_codec_list = NULL;
|
*video_codec_list = NULL;
|
||||||
*audio_codec_list = amr_audio_list;
|
*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 {
|
} else {
|
||||||
GST_LOG ("Format %s not found", format_name);
|
GST_LOG ("Format %s not found", format_name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -2057,6 +2067,7 @@ gst_ffmpeg_caps_to_codecid (const GstCaps * caps, AVCodecContext * context)
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
guint32 fourcc;
|
guint32 fourcc;
|
||||||
|
|
||||||
if (gst_structure_get_fourcc (structure, "fourcc", &fourcc)) {
|
if (gst_structure_get_fourcc (structure, "fourcc", &fourcc)) {
|
||||||
if (fourcc == GST_MAKE_FOURCC ('W', 'V', 'C', '1'))
|
if (fourcc == GST_MAKE_FOURCC ('W', 'V', 'C', '1'))
|
||||||
id = CODEC_ID_VC1;
|
id = CODEC_ID_VC1;
|
||||||
|
@ -2726,6 +2737,9 @@ gst_ffmpeg_get_codecid_longname (enum CodecID codec_id)
|
||||||
case CODEC_ID_XVID:
|
case CODEC_ID_XVID:
|
||||||
name = "XviD video";
|
name = "XviD video";
|
||||||
break;
|
break;
|
||||||
|
case CODEC_ID_GIF:
|
||||||
|
name = "GIF image";
|
||||||
|
break;
|
||||||
case CODEC_ID_PNG:
|
case CODEC_ID_PNG:
|
||||||
name = "PNG image";
|
name = "PNG image";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1162,6 +1162,8 @@ gst_ffmpegdemux_loop (GstPad * pad)
|
||||||
AVStream *avstream;
|
AVStream *avstream;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
GstClockTime timestamp, duration;
|
GstClockTime timestamp, duration;
|
||||||
|
gint outsize;
|
||||||
|
gboolean rawvideo;
|
||||||
|
|
||||||
demux = (GstFFMpegDemux *) (GST_PAD_PARENT (pad));
|
demux = (GstFFMpegDemux *) (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
@ -1222,16 +1224,52 @@ gst_ffmpegdemux_loop (GstPad * pad)
|
||||||
/* prepare to push packet to peer */
|
/* prepare to push packet to peer */
|
||||||
srcpad = stream->pad;
|
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,
|
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 */
|
/* we can ignore not linked */
|
||||||
if (ret == GST_FLOW_NOT_LINKED)
|
if (ret == GST_FLOW_NOT_LINKED)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto no_buffer;
|
goto no_buffer;
|
||||||
|
|
||||||
/* copy the data from packet into the target buffer */
|
/* copy the data from packet into the target buffer
|
||||||
memcpy (GST_BUFFER_DATA (outbuf), pkt.data, pkt.size);
|
* 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_TIMESTAMP (outbuf) = timestamp;
|
||||||
GST_BUFFER_DURATION (outbuf) = duration;
|
GST_BUFFER_DURATION (outbuf) = duration;
|
||||||
|
@ -1498,7 +1536,8 @@ gst_ffmpegdemux_register (GstPlugin * plugin)
|
||||||
!strcmp (in_plugin->name, "wav") ||
|
!strcmp (in_plugin->name, "wav") ||
|
||||||
!strcmp (in_plugin->name, "au") ||
|
!strcmp (in_plugin->name, "au") ||
|
||||||
!strcmp (in_plugin->name, "tta") ||
|
!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;
|
register_typefind_func = FALSE;
|
||||||
|
|
||||||
/* Set the rank of demuxers know to work to MARGINAL.
|
/* 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, "avs") ||
|
||||||
!strcmp (in_plugin->name, "aiff") ||
|
!strcmp (in_plugin->name, "aiff") ||
|
||||||
!strcmp (in_plugin->name, "4xm") ||
|
!strcmp (in_plugin->name, "4xm") ||
|
||||||
!strcmp (in_plugin->name, "yuv4mpegpipe"))
|
!strcmp (in_plugin->name, "yuv4mpegpipe") ||
|
||||||
|
!strcmp (in_plugin->name, "gif"))
|
||||||
rank = GST_RANK_MARGINAL;
|
rank = GST_RANK_MARGINAL;
|
||||||
else
|
else
|
||||||
rank = GST_RANK_NONE;
|
rank = GST_RANK_NONE;
|
||||||
|
|
|
@ -525,6 +525,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
if (best_pad != NULL) {
|
if (best_pad != NULL) {
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
AVPacket pkt;
|
AVPacket pkt;
|
||||||
|
gboolean need_free = FALSE;
|
||||||
|
|
||||||
/* push out current buffer */
|
/* push out current buffer */
|
||||||
buf = gst_collect_pads_pop (ffmpegmux->collect,
|
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),
|
pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf),
|
||||||
ffmpegmux->context->streams[best_pad->padnum]->time_base);
|
ffmpegmux->context->streams[best_pad->padnum]->time_base);
|
||||||
pkt.dts = pkt.pts;
|
pkt.dts = pkt.pts;
|
||||||
|
|
||||||
|
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.data = GST_BUFFER_DATA (buf);
|
||||||
pkt.size = GST_BUFFER_SIZE (buf);
|
pkt.size = GST_BUFFER_SIZE (buf);
|
||||||
|
}
|
||||||
|
|
||||||
pkt.stream_index = best_pad->padnum;
|
pkt.stream_index = best_pad->padnum;
|
||||||
pkt.flags = 0;
|
pkt.flags = 0;
|
||||||
|
|
||||||
|
@ -552,6 +575,8 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
pkt.duration = 0;
|
pkt.duration = 0;
|
||||||
av_write_frame (ffmpegmux->context, &pkt);
|
av_write_frame (ffmpegmux->context, &pkt);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
if (need_free)
|
||||||
|
g_free (pkt.data);
|
||||||
} else {
|
} else {
|
||||||
/* close down */
|
/* close down */
|
||||||
av_write_trailer (ffmpegmux->context);
|
av_write_trailer (ffmpegmux->context);
|
||||||
|
@ -725,6 +750,12 @@ gst_ffmpegmux_register (GstPlugin * plugin)
|
||||||
const gint rates[] = { 44100, 22050, 11025 };
|
const gint rates[] = { 44100, 22050, 11025 };
|
||||||
|
|
||||||
gst_ffmpeg_mux_simple_caps_set_int_list (audiosinkcaps, "rate", 3, rates);
|
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 */
|
/* create a cache for these properties */
|
||||||
|
|
Loading…
Reference in a new issue