mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 15:51:11 +00:00
ext/ffmpeg/: Add simple query functions. Seeking is only cosmetic, it's not actually filled in yet (in ffmpegdec).
Original commit message from CVS: * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_init), (gst_ffmpegdec_query), (gst_ffmpegdec_event), (gst_ffmpegdec_open), (gst_ffmpegdec_negotiate), (gst_ffmpegdec_chain): * ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_init), (gst_ffmpegdemux_close), (gst_ffmpegdemux_src_query), (gst_ffmpegdemux_loop): Add simple query functions. Seeking is only cosmetic, it's not actually filled in yet (in ffmpegdec).
This commit is contained in:
parent
3643177798
commit
1b1044122b
3 changed files with 150 additions and 34 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2005-01-18 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
|
||||
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_init),
|
||||
(gst_ffmpegdec_query), (gst_ffmpegdec_event), (gst_ffmpegdec_open),
|
||||
(gst_ffmpegdec_negotiate), (gst_ffmpegdec_chain):
|
||||
* ext/ffmpeg/gstffmpegdemux.c: (gst_ffmpegdemux_init),
|
||||
(gst_ffmpegdemux_close), (gst_ffmpegdemux_src_query),
|
||||
(gst_ffmpegdemux_loop):
|
||||
Add simple query functions. Seeking is only cosmetic, it's not
|
||||
actually filled in yet (in ffmpegdec).
|
||||
|
||||
2005-01-17 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
|
||||
* ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_init),
|
||||
|
|
|
@ -49,6 +49,14 @@ struct _GstFFMpegDec
|
|||
AVCodecContext *context;
|
||||
AVFrame *picture;
|
||||
gboolean opened;
|
||||
union {
|
||||
struct {
|
||||
gint width, height, fps, fps_base;
|
||||
} video;
|
||||
struct {
|
||||
gint channels, samplerate;
|
||||
} audio;
|
||||
} format;
|
||||
|
||||
/* parsing */
|
||||
AVCodecParserContext *pctx;
|
||||
|
@ -106,6 +114,10 @@ static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass);
|
|||
static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec);
|
||||
static void gst_ffmpegdec_dispose (GObject * object);
|
||||
|
||||
static gboolean gst_ffmpegdec_query (GstPad * pad, GstQueryType type,
|
||||
GstFormat * fmt, gint64 * value);
|
||||
static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event);
|
||||
|
||||
static GstPadLinkReturn gst_ffmpegdec_connect (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static void gst_ffmpegdec_chain (GstPad * pad, GstData * data);
|
||||
|
@ -192,10 +204,14 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
|
|||
ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
|
||||
gst_pad_set_link_function (ffmpegdec->sinkpad, gst_ffmpegdec_connect);
|
||||
gst_pad_set_chain_function (ffmpegdec->sinkpad, gst_ffmpegdec_chain);
|
||||
gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);
|
||||
|
||||
ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
|
||||
gst_pad_use_explicit_caps (ffmpegdec->srcpad);
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);
|
||||
gst_pad_set_event_function (ffmpegdec->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ffmpegdec_event));
|
||||
gst_pad_set_query_function (ffmpegdec->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ffmpegdec_query));
|
||||
gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad);
|
||||
|
||||
/* some ffmpeg data */
|
||||
|
@ -223,6 +239,45 @@ gst_ffmpegdec_dispose (GObject * object)
|
|||
av_free (ffmpegdec->picture);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_ffmpegdec_query (GstPad * pad, GstQueryType type,
|
||||
GstFormat * fmt, gint64 * value)
|
||||
{
|
||||
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad);
|
||||
GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad);
|
||||
GstFormat bfmt = GST_FORMAT_BYTES;
|
||||
|
||||
if (!peer)
|
||||
return FALSE;
|
||||
else if (gst_pad_query (peer, type, fmt, value))
|
||||
return TRUE;
|
||||
/* ok, do bitrate calc... */
|
||||
else if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
|
||||
*fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 ||
|
||||
!gst_pad_query (peer, type, &bfmt, value))
|
||||
return FALSE;
|
||||
|
||||
if (ffmpegdec->pcache && type == GST_QUERY_POSITION)
|
||||
*value -= GST_BUFFER_SIZE (ffmpegdec->pcache);
|
||||
*value *= GST_SECOND / ffmpegdec->context->bit_rate;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_ffmpegdec_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad);
|
||||
GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad);
|
||||
|
||||
if (!peer)
|
||||
return FALSE;
|
||||
else if (gst_pad_send_event (peer, event))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE; /* .. */
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ffmpegdec_close (GstFFMpegDec *ffmpegdec)
|
||||
{
|
||||
|
@ -272,10 +327,29 @@ gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* open a parser if we can - exclude mpeg4 for now... */
|
||||
if (oclass->in_plugin->id != CODEC_ID_MPEG4)
|
||||
/* open a parser if we can - exclude mpeg4, because it is already
|
||||
* framed (divx), mp3 because it doesn't work (?) and mjpeg because
|
||||
* of $(see mpeg4)... */
|
||||
if (oclass->in_plugin->id != CODEC_ID_MPEG4 &&
|
||||
oclass->in_plugin->id != CODEC_ID_MJPEG &&
|
||||
oclass->in_plugin->id != CODEC_ID_MP3)
|
||||
ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id);
|
||||
|
||||
switch (oclass->in_plugin->type) {
|
||||
case CODEC_TYPE_VIDEO:
|
||||
ffmpegdec->format.video.width = 0;
|
||||
ffmpegdec->format.video.height = 0;
|
||||
ffmpegdec->format.video.fps = 0;
|
||||
ffmpegdec->format.video.fps_base = 0;
|
||||
break;
|
||||
case CODEC_TYPE_AUDIO:
|
||||
ffmpegdec->format.audio.samplerate = 0;
|
||||
ffmpegdec->format.audio.channels = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -400,6 +474,25 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
|
|||
(GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
||||
GstCaps *caps;
|
||||
|
||||
switch (oclass->in_plugin->type) {
|
||||
case CODEC_TYPE_VIDEO:
|
||||
if (ffmpegdec->format.video.width == ffmpegdec->context->width &&
|
||||
ffmpegdec->format.video.height == ffmpegdec->context->height &&
|
||||
ffmpegdec->format.video.fps == ffmpegdec->context->frame_rate &&
|
||||
ffmpegdec->format.video.fps_base ==
|
||||
ffmpegdec->context->frame_rate_base)
|
||||
return TRUE;
|
||||
break;
|
||||
case CODEC_TYPE_AUDIO:
|
||||
if (ffmpegdec->format.audio.samplerate ==
|
||||
ffmpegdec->context->sample_rate &&
|
||||
ffmpegdec->format.audio.channels == ffmpegdec->context->channels)
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type,
|
||||
ffmpegdec->context);
|
||||
|
||||
|
@ -472,12 +565,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstData * _data)
|
|||
|
||||
/* parse cache joining */
|
||||
if (ffmpegdec->pcache) {
|
||||
GST_LOG ("Joining %p[%lld/%d]&&%p[%lld/%d]",
|
||||
ffmpegdec->pcache, GST_BUFFER_OFFSET (ffmpegdec->pcache),
|
||||
GST_BUFFER_SIZE (ffmpegdec->pcache), inbuf,
|
||||
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_SIZE (inbuf));
|
||||
inbuf = gst_buffer_join (ffmpegdec->pcache, inbuf);
|
||||
GST_LOG ("done");
|
||||
ffmpegdec->pcache = NULL;
|
||||
bdata = GST_BUFFER_DATA (inbuf);
|
||||
bsize = GST_BUFFER_SIZE (inbuf);
|
||||
|
@ -498,8 +586,7 @@ GST_LOG ("done");
|
|||
|
||||
do {
|
||||
/* parse, if at all possible */
|
||||
if (ffmpegdec->pctx && ffmpegdec->context->codec_id != CODEC_ID_MP3 &&
|
||||
ffmpegdec->context->codec_id != CODEC_ID_MJPEG) {
|
||||
if (ffmpegdec->pctx) {
|
||||
gint res;
|
||||
|
||||
res = av_parser_parse (ffmpegdec->pctx, ffmpegdec->context,
|
||||
|
@ -606,12 +693,10 @@ GST_LOG ("done");
|
|||
if (have_data) {
|
||||
GST_DEBUG ("Decoded data, now pushing");
|
||||
|
||||
if (!GST_PAD_CAPS (ffmpegdec->srcpad)) {
|
||||
if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
|
||||
gst_buffer_unref (outbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (GST_PAD_IS_USABLE (ffmpegdec->srcpad))
|
||||
gst_pad_push (ffmpegdec->srcpad, GST_DATA (outbuf));
|
||||
|
@ -626,7 +711,8 @@ GST_LOG ("done");
|
|||
}
|
||||
} while (bsize > 0);
|
||||
|
||||
if (ffmpegdec->pctx && bsize > 0) {
|
||||
if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) &&
|
||||
bsize > 0) {
|
||||
GST_DEBUG ("Keeping %d bytes of data", bsize);
|
||||
|
||||
ffmpegdec->pcache = gst_buffer_create_sub (inbuf,
|
||||
|
|
|
@ -219,7 +219,7 @@ gst_ffmpegdemux_init (GstFFMpegDemux * demux)
|
|||
for (n = 0; n < MAX_STREAMS; n++) {
|
||||
demux->srcpads[n] = NULL;
|
||||
demux->handled[n] = FALSE;
|
||||
demux->last_ts[n] = 0;
|
||||
demux->last_ts[n] = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
demux->videopads = 0;
|
||||
demux->audiopads = 0;
|
||||
|
@ -240,7 +240,7 @@ gst_ffmpegdemux_close (GstFFMpegDemux * demux)
|
|||
demux->srcpads[n] = NULL;
|
||||
}
|
||||
demux->handled[n] = FALSE;
|
||||
demux->last_ts[n] = 0;
|
||||
demux->last_ts[n] = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
demux->videopads = 0;
|
||||
demux->audiopads = 0;
|
||||
|
@ -358,44 +358,62 @@ gst_ffmpegdemux_src_query (GstPad * pad,
|
|||
{
|
||||
GstFFMpegDemux *demux = (GstFFMpegDemux *) gst_pad_get_parent (pad);
|
||||
AVStream *stream = gst_ffmpegdemux_stream_from_pad (pad);
|
||||
gboolean res = TRUE;
|
||||
|
||||
if (!stream || (*fmt == GST_FORMAT_DEFAULT &&
|
||||
stream->codec.codec_type != CODEC_TYPE_VIDEO))
|
||||
return FALSE;
|
||||
gboolean res = FALSE;
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
switch (*fmt) {
|
||||
case GST_FORMAT_TIME:
|
||||
if (stream) {
|
||||
*value = stream->duration * (GST_SECOND / AV_TIME_BASE);
|
||||
res = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_FORMAT_DEFAULT:
|
||||
if (stream->codec_info_nb_frames) {
|
||||
if (stream->codec_info_nb_frames &&
|
||||
stream->codec.codec_type == CODEC_TYPE_VIDEO) {
|
||||
*value = stream->codec_info_nb_frames;
|
||||
res = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_FORMAT_BYTES:
|
||||
if (demux->videopads + demux->audiopads == 1 &&
|
||||
GST_PAD_PEER (demux->sinkpad) != NULL) {
|
||||
res = gst_pad_query (GST_PAD_PEER (demux->sinkpad),
|
||||
type, fmt, value);
|
||||
}
|
||||
break;
|
||||
} /* else fall-through */
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
switch (*fmt) {
|
||||
case GST_FORMAT_TIME:
|
||||
if (stream &&
|
||||
GST_CLOCK_TIME_IS_VALID (demux->last_ts[stream->index])) {
|
||||
*value = demux->last_ts[stream->index];
|
||||
res = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_FORMAT_DEFAULT:
|
||||
if (stream && stream->codec.codec_type == CODEC_TYPE_VIDEO &&
|
||||
GST_CLOCK_TIME_IS_VALID (demux->last_ts[stream->index])) {
|
||||
res = gst_pad_convert (pad, GST_FORMAT_TIME,
|
||||
demux->last_ts[stream->index], fmt, value);
|
||||
}
|
||||
break;
|
||||
case GST_FORMAT_BYTES:
|
||||
if (demux->videopads + demux->audiopads == 1 &&
|
||||
GST_PAD_PEER (demux->sinkpad) != NULL) {
|
||||
res = gst_pad_query (GST_PAD_PEER (demux->sinkpad),
|
||||
type, fmt, value);
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -629,6 +647,7 @@ gst_ffmpegdemux_loop (GstElement * element)
|
|||
if (pkt.pts != AV_NOPTS_VALUE) {
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = (gdouble) (pkt.pts +
|
||||
stream->start_time) * GST_SECOND / AV_TIME_BASE;
|
||||
demux->last_ts[stream->index] = GST_BUFFER_TIMESTAMP (outbuf);
|
||||
}
|
||||
|
||||
if (pkt.flags & PKT_FLAG_KEY) {
|
||||
|
|
Loading…
Reference in a new issue