diff --git a/src/gstducatividenc.c b/src/gstducatividenc.c
index 56fc1d1e3a5f9aedbabe221bc47ae342ed3b5a63..52a1b098da3c8f61e94fa1b02d708555791cdb87 100644 (file)
--- a/src/gstducatividenc.c
+++ b/src/gstducatividenc.c
#define DEFAULT_BITRATE 2048
#define DEFAULT_RATE_PRESET GST_DUCATI_VIDENC_RATE_PRESET_STORAGE
+#define DEFAULT_INTRA_INTERVAL 16
#define GST_TYPE_DUCATI_VIDENC_RATE_PRESET (gst_ducati_videnc_rate_preset_get_type ())
{
PROP_0,
PROP_BITRATE,
- PROP_RATE_PRESET
+ PROP_RATE_PRESET,
+ PROP_INTRA_INTERVAL
};
static void gst_ducati_videnc_set_property (GObject * object, guint prop_id,
static gboolean gst_ducati_videnc_allocate_params_default (GstDucatiVidEnc *
self, gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz,
gint outargs_sz);
+static gboolean gst_ducati_videnc_is_sync_point_default (GstDucatiVidEnc * enc,
+ int type);
static gboolean gst_ducati_videnc_configure_default (GstDucatiVidEnc * self);
static gboolean gst_ducati_videnc_event (GstBaseVideoEncoder * enc,
GstEvent * event);
enum
{
- GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY = 1, /**< CBR rate control for video conferencing. */
- GST_DUCATI_VIDENC_RATE_PRESET_STORAGE = 2, /**< VBR rate control for local storage (DVD)
+ GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY = IVIDEO_LOW_DELAY, /**< CBR rate control for video conferencing. */
+ GST_DUCATI_VIDENC_RATE_PRESET_STORAGE = IVIDEO_STORAGE, /**< VBR rate control for local storage (DVD)
* recording.
*/
- GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS = 3, /**< Two pass rate control for non real time
+ GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS = IVIDEO_TWOPASS, /**< Two pass rate control for non real time
* applications.
*/
- GST_DUCATI_VIDENC_RATE_PRESET_NONE = 4, /**< No configurable video rate control
+ GST_DUCATI_VIDENC_RATE_PRESET_NONE = IVIDEO_NONE, /**< No configurable video rate control
* mechanism.
*/
- GST_DUCATI_VIDENC_RATE_PRESET_USER_DEFINED = 5,/**< User defined configuration using extended
+ GST_DUCATI_VIDENC_RATE_PRESET_USER_DEFINED = IVIDEO_USER_DEFINED,/**< User defined configuration using extended
* parameters.
*/
};
{GST_DUCATI_VIDENC_RATE_PRESET_LOW_DELAY, "Low Delay", "low-delay"},
{GST_DUCATI_VIDENC_RATE_PRESET_STORAGE, "Storage", "storage"},
{GST_DUCATI_VIDENC_RATE_PRESET_TWOPASS, "Two-Pass", "two-pass"},
+ {GST_DUCATI_VIDENC_RATE_PRESET_NONE, "None", "none"},
+ {GST_DUCATI_VIDENC_RATE_PRESET_USER_DEFINED, "User defined",
+ "user-defined"},
{0, NULL, NULL},
};
klass->allocate_params = gst_ducati_videnc_allocate_params_default;
klass->configure = gst_ducati_videnc_configure_default;
+ klass->is_sync_point = gst_ducati_videnc_is_sync_point_default;
g_object_class_install_property (gobject_class, PROP_BITRATE,
g_param_spec_int ("bitrate", "Bitrate", "Bitrate in kbit/sec", -1,
"H.264 Rate Control",
GST_TYPE_DUCATI_VIDENC_RATE_PRESET, DEFAULT_RATE_PRESET,
G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_INTRA_INTERVAL,
+ g_param_spec_int ("intra-interval", "Intra-frame interval",
+ "Interval between intra frames (keyframes)", 0, INT_MAX,
+ DEFAULT_INTRA_INTERVAL, G_PARAM_READWRITE));
}
static void
self->bitrate = DEFAULT_BITRATE * 1000;
self->rate_preset = DEFAULT_RATE_PRESET;
+ self->intra_interval = DEFAULT_INTRA_INTERVAL;
}
static gboolean
gst_ducati_videnc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
- GstDucatiVidEnc *self = GST_DUCATIVIDENC (object);
+ GstDucatiVidEnc *self;
g_return_if_fail (GST_IS_DUCATIVIDENC (object));
self = GST_DUCATIVIDENC (object);
case PROP_RATE_PRESET:
self->rate_preset = g_value_get_enum (value);
break;
+ case PROP_INTRA_INTERVAL:
+ self->intra_interval = g_value_get_int (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
gst_ducati_videnc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
- GstDucatiVidEnc *self = GST_DUCATIVIDENC (object);
+ GstDucatiVidEnc *self;
g_return_if_fail (GST_IS_DUCATIVIDENC (object));
self = GST_DUCATIVIDENC (object);
case PROP_RATE_PRESET:
g_value_set_enum (value, self->rate_preset);
break;
+ case PROP_INTRA_INTERVAL:
+ g_value_set_int (value, self->intra_interval);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
if (err) {
GST_ERROR_OBJECT (self, "XDM_SETPARAMS err=%d, extendedError=%08x",
err, self->status->extendedError);
+ gst_ducati_log_extended_error_info (self->status->extendedError);
return FALSE;
}
gst_ducati_videnc_configure_default (GstDucatiVidEnc * self)
{
VIDENC2_DynamicParams *dynParams;
+ VIDENC2_Params *params;
const GstVideoState *state;
int i;
if (self->rect.h == 0)
self->rect.h = state->height;
- self->params = (VIDENC2_Params *) self->params;
- self->params->encodingPreset = 0x03;
- self->params->rateControlPreset = self->rate_preset;
- self->params->maxHeight = self->rect.h;
- self->params->maxWidth = self->rect.w;
- self->params->dataEndianness = XDM_BYTE;
- self->params->maxInterFrameInterval = 1;
- self->params->maxBitRate = -1;
- self->params->minBitRate = 0;
- self->params->inputChromaFormat = XDM_YUV_420SP;
- self->params->inputContentType = IVIDEO_PROGRESSIVE;
- self->params->operatingMode = IVIDEO_ENCODE_ONLY;
- self->params->inputDataMode = IVIDEO_ENTIREFRAME;
- self->params->outputDataMode = IVIDEO_ENTIREFRAME;
- self->params->numInputDataUnits = 1;
- self->params->numOutputDataUnits = 1;
+ params = (VIDENC2_Params *) self->params;
+ params->encodingPreset = 0x03;
+ params->rateControlPreset = self->rate_preset;
+ params->maxHeight = self->rect.h;
+ params->maxWidth = self->rect.w;
+ params->dataEndianness = XDM_BYTE;
+ params->maxInterFrameInterval = 1;
+ params->maxBitRate = -1;
+ params->minBitRate = 0;
+ params->inputChromaFormat = XDM_YUV_420SP;
+ params->inputContentType = IVIDEO_PROGRESSIVE;
+ params->operatingMode = IVIDEO_ENCODE_ONLY;
+ params->inputDataMode = IVIDEO_ENTIREFRAME;
+ params->outputDataMode = IVIDEO_ENTIREFRAME;
+ params->numInputDataUnits = 1;
+ params->numOutputDataUnits = 1;
for (i = 0; i < IVIDEO_MAX_NUM_METADATA_PLANES; i++) {
- self->params->metadataType[i] = IVIDEO_METADATAPLANE_NONE;
+ params->metadataType[i] = IVIDEO_METADATAPLANE_NONE;
}
- dynParams = self->dynParams;
dynParams = (VIDENC2_DynamicParams *) self->dynParams;
dynParams->refFrameRate =
dynParams->inputWidth = self->rect.w;
dynParams->inputHeight = self->rect.h;
dynParams->targetBitRate = self->bitrate;
- dynParams->intraFrameInterval = 15;
+ dynParams->intraFrameInterval = self->intra_interval;
dynParams->captureWidth = dynParams->inputWidth;
- dynParams->captureWidth = dynParams->inputWidth = self->rect.w;
dynParams->forceFrame = IVIDEO_NA_FRAME;
dynParams->interFrameInterval = 1;
if (self->outBufs) {
dce_free (self->outBufs);
- self->inBufs = NULL;
+ self->outBufs = NULL;
}
if (self->codec) {
XDAS_Int32 err;
const GstVideoState *state;
int i;
+ GstClockTime ts;
+ GstClockTime t;
state = gst_base_video_encoder_get_state (base_video_encoder);
}
inbuf = gst_buffer_ref (frame->sink_buffer);
+ ts = GST_BUFFER_TIMESTAMP (inbuf);
have_inbuf:
priv_in = get_buffer_priv (self, inbuf, state->width, state->height);
if (priv_in == NULL) {
inbuf = GST_BUFFER (gst_drm_buffer_pool_get (self->input_pool, FALSE));
memcpy (GST_BUFFER_DATA (inbuf), GST_BUFFER_DATA (frame->sink_buffer),
GST_BUFFER_SIZE (frame->sink_buffer));
+ GST_BUFFER_TIMESTAMP (inbuf) = ts;
goto have_inbuf;
}
self->outBufs->descs[0].bufSize.bytes = GST_BUFFER_SIZE (outbuf);
self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
-
self->inArgs->inputID = GPOINTER_TO_INT (inbuf);
+ GST_DEBUG ("Calling VIDENC2_process");
+ t = gst_util_get_timestamp ();
err = VIDENC2_process (self->codec, self->inBufs, self->outBufs,
self->inArgs, self->outArgs);
+ t = gst_util_get_timestamp () - t;
+ GST_DEBUG_OBJECT (self, "VIDENC2_process took %10dns (%d ms)", (gint) t,
+ (gint) (t / 1000000));
if (err) {
GST_WARNING_OBJECT (self, "process failed: err=%d, extendedError=%08x",
- err, self->status->extendedError);
+ err, self->outArgs->extendedError);
+ gst_ducati_log_extended_error_info (self->outArgs->extendedError);
err = VIDENC2_control (self->codec,
XDM_GETSTATUS, (IVIDENC2_DynamicParams *) self->dynParams,
return GST_FLOW_ERROR;
}
- if (self->outArgs->encodedFrameType == IVIDEO_IDR_FRAME)
- frame->is_sync_point = TRUE;
- frame->src_buffer = gst_buffer_new_and_alloc (self->outArgs->bytesGenerated);
- memcpy (GST_BUFFER_DATA (frame->src_buffer),
- GST_BUFFER_DATA (outbuf), self->outArgs->bytesGenerated);
+ if (self->outArgs->bytesGenerated > 0) {
+ frame->is_sync_point =
+ GST_DUCATIVIDENC_GET_CLASS (self)->is_sync_point (self,
+ self->outArgs->encodedFrameType);
+ frame->src_buffer =
+ gst_buffer_new_and_alloc (self->outArgs->bytesGenerated);
+ memcpy (GST_BUFFER_DATA (frame->src_buffer), GST_BUFFER_DATA (outbuf),
+ self->outArgs->bytesGenerated);
+ GST_DEBUG_OBJECT (self, "Encoded frame in %u bytes",
+ self->outArgs->bytesGenerated);
+
+ /* As we can get frames in a different order we sent them (if the codec
+ supports B frames and we set it up for generating those), we need to
+ work out what input frame corresponds to the frame we just got, to
+ keep presentation times correct.
+ It seems that the codec will free buffers in the right order for this,
+ but I can not find anything saying this in the docs, so:
+ - it might be subject to change
+ - it might not be true in all setups
+ - it might not be true for all codecs
+ However, that's the only way I can see to do it. So there's a nice
+ assert below that will blow up if the codec does not free exactly one
+ input frame when it outputs a frame. That doesn't catch all cases,
+ such as when it frees them in the wrong order, but that seems less
+ likely to happen.
+ The timestamp and duration are given to the base class, which will
+ in turn set them onto the encoded buffer. */
+ g_assert (self->outArgs->freeBufID[0] && !self->outArgs->freeBufID[1]);
+ inbuf = GST_BUFFER (self->outArgs->freeBufID[0]);
+ frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (inbuf);
+ frame->presentation_duration = GST_BUFFER_DURATION (inbuf);
+ GST_BUFFER_OFFSET_END (frame->src_buffer) = GST_BUFFER_TIMESTAMP (inbuf);
+ }
gst_buffer_unref (outbuf);
return gst_base_video_encoder_finish_frame (base_video_encoder, frame);
}
+static gboolean
+gst_ducati_videnc_is_sync_point_default (GstDucatiVidEnc * enc, int type)
+{
+ return type == IVIDEO_I_FRAME;
+}
+
static gboolean
gst_ducati_videnc_event (GstBaseVideoEncoder * enc, GstEvent * event)
{