static gboolean
gst_vaapi_decoder_stop(GstVaapiDecoder *decoder);
+static GstBuffer *
+pop_buffer(GstVaapiDecoder *decoder);
+
static gpointer
decoder_thread_cb(gpointer data)
{
GstVaapiDecoder * const decoder = data;
GstVaapiDecoderPrivate * const priv = decoder->priv;
GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
- GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
-
- if (!klass->decode) {
- g_error("unimplemented GstVaapiDecoder::decode() function");
- return NULL;
- }
+ GstBuffer *buffer;
+ g_object_ref(decoder);
while (!priv->decoder_thread_cancel) {
- g_mutex_lock(priv->adapter_mutex);
- while (!gst_adapter_available(priv->adapter)) {
- g_cond_wait(priv->adapter_cond, priv->adapter_mutex);
- if (priv->decoder_thread_cancel)
- break;
- }
- g_mutex_unlock(priv->adapter_mutex);
-
- if (!priv->decoder_thread_cancel) {
- switch (status) {
- case GST_VAAPI_DECODER_STATUS_SUCCESS:
- case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
- GST_DEBUG("decode");
- g_object_ref(decoder);
- status = klass->decode(decoder);
- g_object_unref(decoder);
-
- /* Detect End-of-Stream conditions */
- if (status != GST_VAAPI_DECODER_STATUS_SUCCESS &&
- priv->is_eos &&
- gst_vaapi_decoder_read_avail(decoder) == 0)
- status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
-
- GST_DEBUG("decode frame (status = %d)", status);
- break;
- default:
- /* XXX: something went wrong, simply destroy any
- buffer until this decoder is destroyed */
- g_mutex_lock(priv->adapter_mutex);
- gst_adapter_clear(priv->adapter);
- g_mutex_unlock(priv->adapter_mutex);
-
- /* Signal the main thread we got an error */
- if (status != GST_VAAPI_DECODER_STATUS_END_OF_STREAM)
- gst_vaapi_decoder_push_surface(decoder, NULL);
- break;
- }
- }
-
- /* End-of-Stream reached, decoder thread is no longer necessary */
- if (status == GST_VAAPI_DECODER_STATUS_END_OF_STREAM)
+ buffer = pop_buffer(decoder);
+ priv->decoder_status = klass->decode(decoder, buffer);
+ GST_DEBUG("decode frame (status = %d)", priv->decoder_status);
+ switch (priv->decoder_status) {
+ case GST_VAAPI_DECODER_STATUS_SUCCESS:
+ case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
break;
+ default:
+ priv->decoder_thread_cancel = TRUE;
+ break;
+ }
+ gst_buffer_unref(buffer);
}
+ g_object_unref(decoder);
return NULL;
}
+static inline void
+init_buffer(GstBuffer *buffer, const guchar *buf, guint buf_size)
+{
+ GST_BUFFER_DATA(buffer) = (guint8 *)buf;
+ GST_BUFFER_SIZE(buffer) = buf_size;
+ GST_BUFFER_TIMESTAMP(buffer) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE;
+}
+
+static inline GstBuffer *
+create_eos_buffer(void)
+{
+ GstBuffer *buffer;
+
+ buffer = gst_buffer_new();
+ if (!buffer)
+ return NULL;
+
+ init_buffer(buffer, NULL, 0);
+ GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
+ return buffer;
+}
+
static GstBuffer *
create_buffer(const guchar *buf, guint buf_size, gboolean copy)
{
return NULL;
}
memcpy(buffer->malloc_data, buf, buf_size);
- GST_BUFFER_DATA(buffer) = buffer->malloc_data;
- GST_BUFFER_SIZE(buffer) = buf_size;
- }
- else {
- GST_BUFFER_DATA(buffer) = (guint8 *)buf;
- GST_BUFFER_SIZE(buffer) = buf_size;
+ buf = buffer->malloc_data;
}
+ init_buffer(buffer, buf, buf_size);
return buffer;
}
GstVaapiDecoderPrivate * const priv = decoder->priv;
if (!buffer) {
- priv->is_eos = TRUE;
- return TRUE;
+ buffer = create_eos_buffer();
+ if (!buffer)
+ return FALSE;
}
- g_return_val_if_fail(priv->adapter_mutex && priv->adapter_cond, FALSE);
-
GST_DEBUG("queue encoded data buffer %p (%d bytes)",
buffer, GST_BUFFER_SIZE(buffer));
if (!priv->decoder_thread && !gst_vaapi_decoder_start(decoder))
return FALSE;
- /* XXX: add a mechanism to wait for enough buffer bytes to be consumed */
- g_mutex_lock(priv->adapter_mutex);
- gst_adapter_push(priv->adapter, buffer);
- g_cond_signal(priv->adapter_cond);
- g_mutex_unlock(priv->adapter_mutex);
+ g_async_queue_push(priv->buffers, buffer);
return TRUE;
}
+static GstBuffer *
+pop_buffer(GstVaapiDecoder *decoder)
+{
+ GstVaapiDecoderPrivate * const priv = decoder->priv;
+ GstBuffer *buffer;
+
+ buffer = g_async_queue_pop(priv->buffers);
+ g_return_val_if_fail(buffer, NULL);
+
+ if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer))
+ GST_BUFFER_TIMESTAMP(buffer) = priv->next_ts;
+ return buffer;
+}
+
static void
-unref_surface_cb(gpointer surface, gpointer user_data)
+clear_async_queue(GAsyncQueue *q)
{
- if (surface)
- g_object_unref(GST_VAAPI_SURFACE(surface));
+ guint i, qlen = g_async_queue_length(q);
+
+ for (i = 0; i < qlen; i++)
+ g_object_unref(g_async_queue_pop(q));
}
static void
gst_vaapi_decoder_stop(decoder);
- if (priv->adapter) {
- gst_adapter_clear(priv->adapter);
- g_object_unref(priv->adapter);
- priv->adapter = NULL;
- }
-
- if (priv->adapter_cond) {
- g_cond_free(priv->adapter_cond);
- priv->adapter_cond = NULL;
- }
-
- if (priv->adapter_mutex) {
- g_mutex_free(priv->adapter_mutex);
- priv->adapter_mutex = NULL;
- }
-
if (priv->context) {
g_object_unref(priv->context);
priv->context = NULL;
}
- g_queue_foreach(&priv->surfaces, unref_surface_cb, NULL);
-
- if (priv->surfaces_cond) {
- g_cond_free(priv->surfaces_cond);
- priv->surfaces_cond = NULL;
+ if (priv->buffers) {
+ clear_async_queue(priv->buffers);
+ g_object_unref(priv->buffers);
+ priv->buffers = NULL;
}
- if (priv->surfaces_mutex) {
- g_mutex_free(priv->surfaces_mutex);
- priv->surfaces_mutex = NULL;
+ if (priv->surfaces) {
+ clear_async_queue(priv->surfaces);
+ g_object_unref(priv->surfaces);
+ priv->surfaces = NULL;
}
if (priv->display) {
decoder->priv = priv;
priv->context = NULL;
priv->codec = 0;
- priv->adapter = gst_adapter_new();
- priv->adapter_mutex = g_mutex_new();
- priv->adapter_cond = g_cond_new();
- priv->surfaces_mutex = g_mutex_new();
- priv->surfaces_cond = g_cond_new();
+ priv->fps_n = 1000;
+ priv->fps_d = 30;
+ priv->next_ts = 0;
+ priv->buffers = g_async_queue_new();
+ priv->surfaces = g_async_queue_new();
priv->decoder_thread = NULL;
priv->decoder_thread_cancel = FALSE;
- priv->is_eos = FALSE;
-
- g_queue_init(&priv->surfaces);
}
/**
GstVaapiDecoderPrivate * const priv = decoder->priv;
if (priv->decoder_thread) {
+ push_buffer(decoder, NULL);
priv->decoder_thread_cancel = TRUE;
- if (priv->adapter_mutex && priv->adapter_cond) {
- g_mutex_lock(priv->adapter_mutex);
- g_cond_signal(priv->adapter_cond);
- g_mutex_unlock(priv->adapter_mutex);
- }
g_thread_join(priv->decoder_thread);
priv->decoder_thread = NULL;
}
}
/**
+ * gst_vaapi_decoder_get_frame_rate:
+ * @decoder: a #GstVaapiDecoder
+ * @num: return location for the numerator of the frame rate
+ * @den: return location for the denominator of the frame rate
+ *
+ * Retrieves the current frame rate as the fraction @num / @den. The
+ * default frame rate is 30 fps.
+ */
+void
+gst_vaapi_decoder_get_frame_rate(
+ GstVaapiDecoder *decoder,
+ guint *num,
+ guint *den
+)
+{
+ g_return_if_fail(GST_VAAPI_IS_DECODER(decoder));
+
+ if (num)
+ *num = decoder->priv->fps_n;
+
+ if (den)
+ *den = decoder->priv->fps_d;
+}
+
+/**
+ * gst_vaapi_decoder_set_frame_rate:
+ * @decoder: a #GstVaapiDecoder
+ * @num: the numerator of the frame rate
+ * @den: the denominator of the frame rate
+ *
+ * Sets the frame rate for the stream to @num / @den. By default, the
+ * decoder will use the frame rate encoded in the elementary stream.
+ * If none is available, the decoder will default to 30 fps.
+ */
+void
+gst_vaapi_decoder_set_frame_rate(
+ GstVaapiDecoder *decoder,
+ guint num,
+ guint den
+)
+{
+ g_return_if_fail(GST_VAAPI_IS_DECODER(decoder));
+
+ decoder->priv->fps_n = num;
+ decoder->priv->fps_d = den;
+}
+
+/**
* gst_vaapi_decoder_put_buffer_data:
* @decoder: a #GstVaapiDecoder
* @buf: pointer to buffer data
* or %NULL if none is available (e.g. an error). Caller owns the
* returned object. g_object_unref() after usage.
*/
-static GstVaapiSurface *
+static GstVaapiSurfaceProxy *
_gst_vaapi_decoder_get_surface(
GstVaapiDecoder *decoder,
- GTimeVal *timeout,
+ GTimeVal *end_time,
GstVaapiDecoderStatus *pstatus
)
{
GstVaapiDecoderPrivate * const priv = decoder->priv;
+ GstVaapiDecoderStatus status;
GstVaapiSurface *surface;
+ GstVaapiSurfaceProxy *proxy = NULL;
- g_mutex_lock(priv->surfaces_mutex);
- while (g_queue_is_empty(&priv->surfaces))
- if (!g_cond_timed_wait(priv->surfaces_cond, priv->surfaces_mutex, timeout))
- break;
- surface = g_queue_pop_head(&priv->surfaces);
- g_mutex_unlock(priv->surfaces_mutex);
-
- if (surface)
- *pstatus = GST_VAAPI_DECODER_STATUS_SUCCESS;
- else {
- g_mutex_lock(priv->adapter_mutex);
- if (gst_adapter_available(priv->adapter))
- *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
- else if (timeout)
- *pstatus = GST_VAAPI_DECODER_STATUS_TIMEOUT;
- else
- *pstatus = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
- g_mutex_unlock(priv->adapter_mutex);
+ surface = g_async_queue_timed_pop(priv->surfaces, end_time);
+
+ if (surface) {
+ proxy = gst_vaapi_surface_proxy_new(priv->context, surface);
+ status = (proxy ?
+ GST_VAAPI_DECODER_STATUS_SUCCESS :
+ GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED);
+ g_object_unref(surface);
}
- return surface;
+ else if (end_time)
+ status = GST_VAAPI_DECODER_STATUS_TIMEOUT;
+ else
+ status = priv->decoder_status;
+
+ if (pstatus)
+ *pstatus = status;
+ return proxy;
}
GstVaapiSurfaceProxy *
GstVaapiDecoderStatus *pstatus
)
{
- GstVaapiSurfaceProxy *proxy = NULL;
- GstVaapiSurface *surface;
- GstVaapiDecoderStatus status;
-
g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
- surface = _gst_vaapi_decoder_get_surface(decoder, NULL, &status);
- if (surface) {
- proxy = gst_vaapi_surface_proxy_new(decoder->priv->context, surface);
- if (!proxy)
- status = GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
- g_object_unref(surface);
- }
-
- if (pstatus)
- *pstatus = status;
- return proxy;
+ return _gst_vaapi_decoder_get_surface(decoder, NULL, pstatus);
}
/**
GstVaapiDecoderStatus *pstatus
)
{
- GstVaapiSurfaceProxy *proxy = NULL;
- GstVaapiSurface *surface;
- GstVaapiDecoderStatus status;
GTimeVal end_time;
g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
g_get_current_time(&end_time);
g_time_val_add(&end_time, timeout);
- surface = _gst_vaapi_decoder_get_surface(decoder, &end_time, &status);
- if (surface) {
- proxy = gst_vaapi_surface_proxy_new(decoder->priv->context, surface);
- if (!proxy)
- status = GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
- g_object_unref(surface);
- }
-
- if (pstatus)
- *pstatus = status;
- return proxy;
+ return _gst_vaapi_decoder_get_surface(decoder, &end_time, pstatus);
}
gboolean
return priv->context != NULL;
}
-guint
-gst_vaapi_decoder_copy(
- GstVaapiDecoder *decoder,
- guint offset,
- guchar *buf,
- guint buf_size
-)
-{
- GstVaapiDecoderPrivate * const priv = decoder->priv;
- guint avail;
-
- if (!buf || !buf_size)
- return 0;
-
- avail = gst_vaapi_decoder_read_avail(decoder);
- if (offset >= avail)
- return 0;
- if (buf_size > avail - offset)
- buf_size = avail - offset;
-
- if (buf_size > 0) {
- g_mutex_lock(priv->adapter_mutex);
- gst_adapter_copy(priv->adapter, buf, offset, buf_size);
- g_mutex_unlock(priv->adapter_mutex);
- }
- return buf_size;
-}
-
-guint
-gst_vaapi_decoder_read_avail(GstVaapiDecoder *decoder)
-{
- GstVaapiDecoderPrivate * const priv = decoder->priv;
- guint avail;
-
- g_mutex_lock(priv->adapter_mutex);
- avail = gst_adapter_available(priv->adapter);
- g_mutex_unlock(priv->adapter_mutex);
- return avail;
-}
-
-guint
-gst_vaapi_decoder_read(GstVaapiDecoder *decoder, guchar *buf, guint buf_size)
-{
- buf_size = gst_vaapi_decoder_copy(decoder, 0, buf, buf_size);
- if (buf_size > 0)
- gst_vaapi_decoder_flush(decoder, buf_size);
- return buf_size;
-}
-
-void
-gst_vaapi_decoder_flush(GstVaapiDecoder *decoder, guint buf_size)
-{
- GstVaapiDecoderPrivate * const priv = decoder->priv;
- guint avail;
-
- if (!buf_size)
- return;
-
- avail = gst_vaapi_decoder_read_avail(decoder);
- if (buf_size > avail)
- buf_size = avail;
-
- g_mutex_lock(priv->adapter_mutex);
- gst_adapter_flush(priv->adapter, buf_size);
- g_mutex_unlock(priv->adapter_mutex);
-}
-
gboolean
gst_vaapi_decoder_push_surface(
GstVaapiDecoder *decoder,
{
GstVaapiDecoderPrivate * const priv = decoder->priv;
- if (surface)
- GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
- GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
- else
- GST_DEBUG("queue null surface to signal an error");
+ g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
+
+ GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
+ GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
- g_mutex_lock(priv->surfaces_mutex);
- g_queue_push_tail(&priv->surfaces, surface ? g_object_ref(surface) : NULL);
- g_cond_signal(priv->surfaces_cond);
- g_mutex_unlock(priv->surfaces_mutex);
+ g_async_queue_push(priv->surfaces, g_object_ref(surface));
return TRUE;
}
GST_VAAPI_TYPE_DECODER_FFMPEG, \
GstVaapiDecoderFfmpegPrivate))
-/** Default I/O buffer size (32 KB) */
-#define DEFAULT_IOBUF_SIZE (32 * 1024)
-
typedef struct _GstVaapiContextFfmpeg GstVaapiContextFfmpeg;
struct _GstVaapiContextFfmpeg {
struct vaapi_context base;
};
struct _GstVaapiDecoderFfmpegPrivate {
- AVPacket packet;
AVFrame *frame;
- guchar *iobuf;
- guint iobuf_pos;
- guint iobuf_size;
- ByteIOContext ioctx;
- AVFormatContext *fmtctx;
+ AVCodecParserContext *pctx;
AVCodecContext *avctx;
GstVaapiContextFfmpeg *vactx;
- guint video_stream_index;
guint is_constructed : 1;
};
return CODEC_ID_NONE;
}
-/** Converts codec to FFmpeg raw bitstream format */
-static const gchar *
-get_raw_format_from_codec(GstVaapiCodec codec)
-{
- switch (codec) {
- case GST_VAAPI_CODEC_MPEG1: return "mpegvideo";
- case GST_VAAPI_CODEC_MPEG2: return "mpegvideo";
- case GST_VAAPI_CODEC_MPEG4: return "m4v";
- case GST_VAAPI_CODEC_H263: return "h263";
- case GST_VAAPI_CODEC_H264: return "h264";
- case GST_VAAPI_CODEC_VC1: return "vc1";
- }
- return NULL;
-}
-
/** Finds a suitable profile from FFmpeg context */
static GstVaapiProfile
get_profile(AVCodecContext *avctx)
return 0;
}
-/** Probes FFmpeg format from input stream */
-static AVInputFormat *
-get_probed_format(GstVaapiDecoder *decoder)
-{
- GstVaapiDecoderFfmpegPrivate * const priv =
- GST_VAAPI_DECODER_FFMPEG(decoder)->priv;
-
- AVProbeData pd;
- pd.filename = "";
- pd.buf = priv->iobuf;
- pd.buf_size = MIN(gst_vaapi_decoder_read_avail(decoder), priv->iobuf_size);
- if (!gst_vaapi_decoder_copy(decoder, 0, pd.buf, pd.buf_size))
- return FALSE;
-
- GST_DEBUG("probing format from buffer %p [%d bytes]", pd.buf, pd.buf_size);
- return av_probe_input_format(&pd, 1);
-}
-
-/** Tries to get an FFmpeg format from the raw bitstream */
-static AVInputFormat *
-get_raw_format(GstVaapiDecoder *decoder)
-{
- const gchar *raw_format;
-
- raw_format = get_raw_format_from_codec(GST_VAAPI_DECODER_CODEC(decoder));
- if (!raw_format)
- return NULL;
-
- GST_DEBUG("trying raw format %s", raw_format);
- return av_find_input_format(raw_format);
-}
-
-/** Flushes n bytes from the stream */
-static void
-stream_flush(GstVaapiDecoder *decoder, int buf_size)
-{
- GstVaapiDecoderFfmpegPrivate * const priv =
- GST_VAAPI_DECODER_FFMPEG(decoder)->priv;
-
- gst_vaapi_decoder_flush(decoder, buf_size);
- if (priv->iobuf_pos > buf_size)
- priv->iobuf_pos -= buf_size;
- else
- priv->iobuf_pos = 0;
-}
-
-/** Reads one packet */
-static int
-stream_read(void *opaque, uint8_t *buf, int buf_size)
-{
- GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(opaque);
- GstVaapiDecoderFfmpegPrivate * const priv =
- GST_VAAPI_DECODER_FFMPEG(decoder)->priv;
-
- if (buf_size > 0) {
- buf_size = gst_vaapi_decoder_copy(
- decoder,
- priv->iobuf_pos,
- buf, buf_size
- );
- priv->iobuf_pos += buf_size;
- }
- return buf_size;
-}
-
-/** Seeks into stream */
-static int64_t
-stream_seek(void *opaque, int64_t offset, int whence)
-{
- GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(opaque);
- GstVaapiDecoderFfmpegPrivate * const priv =
- GST_VAAPI_DECODER_FFMPEG(decoder)->priv;
-
- /* If we parsed the headers (decoder is constructed), we can no
- longer seek into the stream */
- if (priv->is_constructed &&
- !((whence == SEEK_SET || whence == SEEK_CUR) && offset == 0))
- return -1;
-
- switch (whence) {
- case SEEK_SET:
- priv->iobuf_pos = offset;
- break;
- case SEEK_CUR:
- priv->iobuf_pos += offset;
- break;
- case SEEK_END:
- priv->iobuf_pos = gst_vaapi_decoder_read_avail(decoder) + offset;
- break;
- default:
- return -1;
- }
- return priv->iobuf_pos;
-}
-
/** AVCodecContext.get_format() implementation */
static enum PixelFormat
gst_vaapi_decoder_ffmpeg_get_format(AVCodecContext *avctx, const enum PixelFormat *fmt)
{
GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
- if (priv->avctx) {
- avcodec_close(priv->avctx);
- priv->avctx = NULL;
- }
-
if (priv->vactx) {
g_free(priv->vactx);
priv->vactx = NULL;
}
- if (priv->fmtctx) {
- av_close_input_stream(priv->fmtctx);
- priv->fmtctx = NULL;
+ if (priv->avctx) {
+ avcodec_close(priv->avctx);
+ priv->avctx = NULL;
}
- if (priv->iobuf) {
- g_free(priv->iobuf);
- priv->iobuf = NULL;
- priv->iobuf_pos = 0;
+ if (priv->pctx) {
+ av_parser_close(priv->pctx);
+ priv->pctx = NULL;
}
av_freep(&priv->frame);
- av_free_packet(&priv->packet);
}
static gboolean
GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(ffdecoder);
GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
GstVaapiCodec codec = GST_VAAPI_DECODER_CODEC(decoder);
- enum CodecID codec_id = get_codec_id_from_codec(codec);
- typedef AVInputFormat *(*GetFormatFunc)(GstVaapiDecoder *);
- GetFormatFunc get_format[2];
- AVInputFormat *format;
- AVStream *video_stream;
+ enum CodecID codec_id;
AVCodec *ffcodec;
- guint i;
- if (!priv->vactx) {
- priv->vactx = g_new(GstVaapiContextFfmpeg, 1);
- if (!priv->vactx)
- return FALSE;
- }
- memset(&priv->vactx->base, 0, sizeof(priv->vactx->base));
- priv->vactx->decoder = ffdecoder;
+ codec_id = get_codec_id_from_codec(codec);
+ if (codec_id == CODEC_ID_NONE)
+ return FALSE;
+
+ ffcodec = avcodec_find_decoder(codec_id);
+ if (!ffcodec)
+ return FALSE;
if (!priv->frame) {
priv->frame = avcodec_alloc_frame();
return FALSE;
}
- if (!priv->iobuf) {
- priv->iobuf = g_malloc0(priv->iobuf_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!priv->iobuf)
+ if (!priv->avctx) {
+ priv->avctx = avcodec_alloc_context();
+ if (!priv->avctx)
return FALSE;
}
- get_format[ !codec] = get_raw_format;
- get_format[!!codec] = get_probed_format;
- for (i = 0; i < 2; i++) {
- format = get_format[i](decoder);
- if (!format)
- continue;
-
- priv->iobuf_pos = 0;
- init_put_byte(
- &priv->ioctx,
- priv->iobuf,
- priv->iobuf_size,
- 0, /* write flags */
- ffdecoder,
- stream_read,
- NULL, /* no packet writer callback */
- stream_seek
- );
- priv->ioctx.is_streamed = 1;
-
- if (av_open_input_stream(&priv->fmtctx, &priv->ioctx, "", format, NULL) < 0)
- continue;
-
- if (av_find_stream_info(priv->fmtctx) >= 0)
- break;
-
- av_close_input_stream(priv->fmtctx);
- priv->fmtctx = NULL;
- }
- if (!priv->fmtctx)
- return FALSE;
-
- if (av_find_stream_info(priv->fmtctx) < 0)
- return FALSE;
- dump_format(priv->fmtctx, 0, "", 0);
-
- video_stream = NULL;
- for (i = 0; i < priv->fmtctx->nb_streams; i++) {
- AVStream * const stream = priv->fmtctx->streams[i];
- if (!video_stream &&
- stream->codec->codec_type == CODEC_TYPE_VIDEO &&
- (codec ? (stream->codec->codec_id == codec_id) : 1)) {
- video_stream = stream;
- }
- else
- stream->discard = AVDISCARD_ALL;
+ if (!priv->vactx) {
+ priv->vactx = g_new(GstVaapiContextFfmpeg, 1);
+ if (!priv->vactx)
+ return FALSE;
}
- if (!video_stream)
- return FALSE;
+ memset(&priv->vactx->base, 0, sizeof(priv->vactx->base));
+ priv->vactx->decoder = ffdecoder;
- priv->video_stream_index = video_stream->index;
- priv->avctx = video_stream->codec;
priv->avctx->hwaccel_context = priv->vactx;
priv->avctx->get_format = gst_vaapi_decoder_ffmpeg_get_format;
priv->avctx->get_buffer = gst_vaapi_decoder_ffmpeg_get_buffer;
priv->avctx->draw_horiz_band = NULL;
priv->avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
- ffcodec = avcodec_find_decoder(priv->avctx->codec_id);
- if (!ffcodec || avcodec_open(priv->avctx, ffcodec) < 0)
+ if (priv->pctx)
+ av_parser_close(priv->pctx);
+ priv->pctx = av_parser_init(codec_id);
+ if (!priv->pctx)
return FALSE;
- av_init_packet(&priv->packet);
+ /* XXX: lock display? */
+ if (avcodec_open(priv->avctx, ffcodec) < 0)
+ return FALSE;
return TRUE;
}
-static GstVaapiSurface *
+static GstVaapiDecoderStatus
decode_frame(GstVaapiDecoderFfmpeg *ffdecoder, guchar *buf, guint buf_size)
{
GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
GstVaapiDisplay * const display = GST_VAAPI_DECODER_DISPLAY(ffdecoder);
- GstVaapiSurface *surface = NULL;
+ GstVaapiSurface *surface;
int bytes_read, got_picture = 0;
GST_VAAPI_DISPLAY_LOCK(display);
buf, buf_size
);
GST_VAAPI_DISPLAY_UNLOCK(display);
+ if (bytes_read < 0)
+ return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+ if (!got_picture)
+ return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+ surface = gst_vaapi_context_find_surface_by_id(
+ GST_VAAPI_DECODER_CONTEXT(ffdecoder),
+ GPOINTER_TO_UINT(priv->frame->data[3])
+ );
+ if (!surface)
+ return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE;
- if (bytes_read > 0)
- stream_flush(GST_VAAPI_DECODER_CAST(ffdecoder), bytes_read);
-
- if (got_picture) {
- surface = gst_vaapi_context_find_surface_by_id(
- GST_VAAPI_DECODER_CONTEXT(ffdecoder),
- GPOINTER_TO_UINT(priv->frame->data[3])
- );
- }
- return surface;
+ gst_vaapi_decoder_push_surface(GST_VAAPI_DECODER_CAST(ffdecoder), surface);
+ return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
GstVaapiDecoderStatus
-gst_vaapi_decoder_ffmpeg_decode(GstVaapiDecoder *decoder)
+gst_vaapi_decoder_ffmpeg_decode(GstVaapiDecoder *decoder, GstBuffer *buffer)
{
GstVaapiDecoderFfmpeg * const ffdecoder = GST_VAAPI_DECODER_FFMPEG(decoder);
GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
- GstVaapiSurface *surface = NULL;
- AVPacket packet;
+ GstVaapiDecoderStatus status;
+ GstClockTime inbuf_ts;
+ guchar *inbuf, *outbuf;
+ gint inbuf_size, outbuf_size;
+ gboolean got_frame;
if (!priv->is_constructed) {
priv->is_constructed = gst_vaapi_decoder_ffmpeg_create(ffdecoder);
- if (!priv->is_constructed) {
- gst_vaapi_decoder_ffmpeg_destroy(ffdecoder);
+ if (!priv->is_constructed)
return GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED;
- }
}
- av_init_packet(&packet);
- while (av_read_frame(priv->fmtctx, &packet) == 0) {
- if (packet.stream_index != priv->video_stream_index)
- continue;
+ inbuf = GST_BUFFER_DATA(buffer);
+ inbuf_size = GST_BUFFER_SIZE(buffer);
+ inbuf_ts = GST_BUFFER_TIMESTAMP(buffer);
+
+ do {
+ int parsed_size = av_parser_parse(
+ priv->pctx,
+ priv->avctx,
+ &outbuf, &outbuf_size,
+ inbuf, inbuf_size,
+ inbuf_ts, inbuf_ts
+ );
+ got_frame = outbuf && outbuf_size > 0;
+ GST_DEBUG("outbuf %p (%d bytes), got frame %d, parsed size %d",
+ outbuf, outbuf_size, got_frame, parsed_size);
- surface = decode_frame(ffdecoder, packet.data, packet.size);
- if (surface) /* decode a single frame only */
- break;
- }
- if (!surface)
- surface = decode_frame(ffdecoder, NULL, 0);
- av_free_packet(&packet);
+ if (parsed_size > 0) {
+ inbuf += parsed_size;
+ inbuf_size -= parsed_size;
+ }
+ } while (!got_frame && inbuf_size > 0);
- if (surface && gst_vaapi_decoder_push_surface(decoder, surface))
- return GST_VAAPI_DECODER_STATUS_SUCCESS;
- return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+ if (!got_frame && !GST_BUFFER_IS_EOS(buffer))
+ return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+ return decode_frame(ffdecoder, outbuf, outbuf_size);
}
static void
priv = GST_VAAPI_DECODER_FFMPEG_GET_PRIVATE(decoder);
decoder->priv = priv;
priv->frame = NULL;
- priv->iobuf = NULL;
- priv->iobuf_pos = 0;
- priv->iobuf_size = DEFAULT_IOBUF_SIZE;
- priv->fmtctx = NULL;
+ priv->pctx = NULL;
priv->avctx = NULL;
priv->vactx = NULL;
- priv->video_stream_index = 0;
priv->is_constructed = FALSE;
-
- av_init_packet(&priv->packet);
}
/**