{
GstH264Parse *h264parse = GST_H264_PARSE (parse);
GstBuffer *buffer = frame->buffer;
+ GstMapInfo map;
guint8 *data;
- guint size;
- gint current_off = 0;
+ gsize size;
+ guint current_off = 0;
- gboolean drain;
+ gboolean drain, nonext;
GstH264NalParser *nalparser = h264parse->nalparser;
GstH264NalUnit nalu;
+ GstH264ParserResult pres;
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
/* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
- if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
+ if (G_UNLIKELY (size < 5)) {
+ gst_buffer_unmap (buffer, &map);
return FALSE;
+ }
/* need to configure aggregation */
if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE))
GST_LOG_OBJECT (h264parse, "resuming frame parsing");
}
- drain = FALSE;
- nalu = h264parse->nalu;
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
+ drain = GST_BASE_PARSE_DRAINING (parse);
+ nonext = FALSE;
+
current_off = h264parse->current_off;
+ if (current_off < 0)
+ current_off = 0;
+ g_assert (current_off < size);
+ GST_DEBUG_OBJECT (h264parse, "last parse position %d", current_off);
+
+ /* check for initial skip */
+ if (h264parse->current_off == -1) {
+ pres =
+ gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
+ size, &nalu);
+ switch (pres) {
+ case GST_H264_PARSER_OK:
+ if (nalu.sc_offset > 0) {
+ *skipsize = nalu.sc_offset;
+ goto skip;
+ }
+ break;
+ case GST_H264_PARSER_NO_NAL:
+ *skipsize = size - 3;
+ goto skip;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
- GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off);
while (TRUE) {
- GstH264ParserResult pres;
-
- if (h264parse->packetized)
+ if (h264parse->packetized_chunked)
pres =
gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
size, &nalu);
}
end:
- *skipsize = h264parse->nalu.sc_offset;
- *framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset;
- h264parse->current_off = current_off;
+ *framesize = nalu.offset + nalu.size;
+
+ gst_buffer_unmap (buffer, &map);
return TRUE;
- parsing_error:
- GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
-
more:
/* ask for best next available */
*framesize = G_MAXUINT;
- if (!h264parse->nalu.size) {
- /* skip up to initial startcode */
- *skipsize = h264parse->nalu.sc_offset;
- /* but mind some stuff will have been skipped */
- g_assert (current_off >= *skipsize);
- current_off -= *skipsize;
- h264parse->nalu.sc_offset = 0;
- } else {
- *skipsize = 0;
- }
+ *skipsize = 0;
/* Restart parsing from here next time */
- h264parse->current_off = current_off;
+ if (current_off > 0)
+ h264parse->current_off = current_off;
+ /* Fall-through. */
+out:
+ gst_buffer_unmap (buffer, &map);
return FALSE;
- invalid:
+ skip:
+ GST_DEBUG_OBJECT (h264parse, "skipping %d", *skipsize);
gst_h264_parse_reset_frame (h264parse);
- return FALSE;
+ goto out;
}
/* byte together avc codec data based on collected pps and sps so far */
nalu.data + nalu.offset, nalu.size);
/* at least this should make sense */
GST_BUFFER_TIMESTAMP (sub) = GST_BUFFER_TIMESTAMP (buffer);
- GST_LOG_OBJECT (h264parse, "pushing NAL of size %d", nalu.size);
+ /* transfer flags (e.g. DISCONT) for first fragment */
+ if (nalu.offset <= nl)
+ gst_buffer_copy_metadata (sub, buffer, GST_BUFFER_COPY_FLAGS);
+ /* in reverse playback, baseparse gathers buffers, so we cannot
+ * guarantee a buffer to contain a single whole NALU */
+ h264parse->packetized_chunked =
+ (GST_BASE_PARSE (h264parse)->segment.rate > 0.0);
+ h264parse->packetized_last =
+ (nalu.offset + nalu.size + nl >= GST_BUFFER_SIZE (buffer));
+ GST_LOG_OBJECT (h264parse, "pushing NAL of size %d, last = %d",
+ nalu.size, h264parse->packetized_last);
- ret = h264parse->parse_chain (pad, sub);
+ ret = h264parse->parse_chain (pad, parent, sub);
} else {
/* pass-through: no looking for frames (and nal processing),
* so need to parse to collect data here */
CloseHandle (shared.hidden_window_created_signal);
- goto failed;
+ if (!shared.d3ddev)
++ goto failed;
+
GST_DEBUG ("Successfully created Direct3D hidden window, handle: %p",
shared.hidden_window_handle);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
- gst_d3dvideosink_initialize_direct3d (sink);
+ if (!gst_d3dvideosink_initialize_direct3d (sink))
- return GST_STATE_CHANGE_FAILURE;
++ return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
break;
return TRUE;
}
- static GstFlowReturn
- gst_d3dvideosink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
+ static void
+ gst_d3dvideosink_flush_gpu (GstD3DVideoSink * sink)
{
- GstD3DVideoSink *sink = GST_D3DVIDEOSINK (vsink);
+ LPDIRECT3DQUERY9 pEventQuery = NULL;
- GST_D3DVIDEOSINK_SHARED_D3D_DEV_LOCK GST_D3DVIDEOSINK_SWAP_CHAIN_LOCK (sink);
- {
- HRESULT hr;
- LPDIRECT3DSURFACE9 backBuffer;
+ IDirect3DDevice9_CreateQuery (sink->d3ddev, D3DQUERYTYPE_EVENT, &pEventQuery);
+ if (pEventQuery) {
+ IDirect3DQuery9_Issue (pEventQuery, D3DISSUE_END);
+ /* Empty the command buffer and wait until the GPU is idle. */
+ while (S_FALSE == IDirect3DQuery9_GetData (pEventQuery, NULL, 0,
+ D3DGETDATA_FLUSH));
+ IDirect3DQuery9_Release (pEventQuery);
+ }
+ }
- if (!shared.d3ddev) {
- if (!shared.device_lost) {
- GST_WARNING ("No Direct3D device has been created, stopping");
- goto error;
- } else {
- GST_WARNING
- ("Direct3D device is lost. Maintaining flow until it has been reset.");
- goto success;
+ static void
+ gst_d3dvideosink_wait_for_vsync (GstD3DVideoSink * sink)
+ {
+ if (sink->d3dpp.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
+ D3DRASTER_STATUS raster_stat;
+ D3DDISPLAYMODE d3ddm;
+ UINT lastScanline = 0;
+ UINT vblankStart = 0;
+ HANDLE thdl = GetCurrentThread ();
+ int prio = GetThreadPriority (thdl);
+ ZeroMemory (&d3ddm, sizeof (d3ddm));
+
+ IDirect3DDevice9_GetDisplayMode (sink->d3ddev, 0, &d3ddm);
+ vblankStart = d3ddm.Height - 10;
+ SetThreadPriority (thdl, THREAD_PRIORITY_TIME_CRITICAL);
+ do {
+ if (FAILED (IDirect3DDevice9_GetRasterStatus (sink->d3ddev, 0,
+ &raster_stat))) {
+ GST_ERROR_OBJECT (sink, "GetRasterStatus failed");
}
- }
-
- if (!sink->d3d_offscreen_surface) {
- GST_WARNING ("No Direct3D offscreen surface has been created, stopping");
- goto error;
- }
+ break;
+ if (!raster_stat.InVBlank) {
+ if (raster_stat.ScanLine < lastScanline) {
+ GST_INFO_OBJECT (sink, "missed last vsync curr : %d",
+ raster_stat.ScanLine);
+ break;
+ }
+ lastScanline = raster_stat.ScanLine;
+ SwitchToThread ();
+ }
+ } while (raster_stat.ScanLine < vblankStart);
+ SetThreadPriority (thdl, prio);
+ }
+ }
- if (!sink->d3d_swap_chain) {
- GST_WARNING ("No Direct3D swap chain has been created, stopping");
- goto error;
- }
+ static GstFlowReturn
+ gst_d3dvideosink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
+ {
+ GstD3DVideoSink *sink = GST_D3DVIDEOSINK (vsink);
+ LPDIRECT3DSURFACE9 drawSurface = NULL;
- if (sink->window_closed) {
- GST_WARNING ("Window has been closed, stopping");
+ GST_D3DVIDEOSINK_SWAP_CHAIN_LOCK (sink);
+ if (!sink->d3ddev) {
+ if (!shared.device_lost) {
+ GST_ERROR_OBJECT (sink, "No Direct3D device has been created, stopping");
goto error;
+ } else {
+ GST_WARNING_OBJECT (sink,
+ "Direct3D device is lost. Maintaining flow until it has been reset.");
+ goto success;
}
+ }
- if (sink->window_handle && !sink->is_new_window) {
- if (shared.d3ddev) {
- gint win_width = 0, win_height = 0;
- D3DPRESENT_PARAMETERS d3dpp;
-
- ZeroMemory (&d3dpp, sizeof (d3dpp));
-
- if (gst_d3dvideosink_window_size (sink, &win_width, &win_height)) {
- IDirect3DSwapChain9_GetPresentParameters (sink->d3d_swap_chain,
- &d3dpp);
- if ((d3dpp.BackBufferWidth > 0 && d3dpp.BackBufferHeight > 0
- && win_width != d3dpp.BackBufferWidth)
- || win_height != d3dpp.BackBufferHeight)
- gst_d3dvideosink_resize_swap_chain (sink, win_width, win_height);
- }
- }
- }
-
- /* Set the render target to our swap chain */
- IDirect3DSwapChain9_GetBackBuffer (sink->d3d_swap_chain, 0,
- D3DBACKBUFFER_TYPE_MONO, &backBuffer);
- IDirect3DDevice9_SetRenderTarget (shared.d3ddev, 0, backBuffer);
- IDirect3DSurface9_Release (backBuffer);
+ if (sink->window_closed) {
+ GST_ERROR_OBJECT (sink, "Window has been closed, stopping");
+ goto error;
+ }
- /* Clear the target */
- IDirect3DDevice9_Clear (shared.d3ddev, 0, NULL, D3DCLEAR_TARGET,
- D3DCOLOR_XRGB (0, 0, 0), 1.0f, 0);
- if (SUCCEEDED (IDirect3DDevice9_BeginScene (shared.d3ddev))) {
- if (GST_BUFFER_DATA (buffer)) {
- D3DLOCKED_RECT lr;
- guint8 *dest, *source;
- int srcstride, dststride, i;
-
- IDirect3DSurface9_LockRect (sink->d3d_offscreen_surface, &lr, NULL, 0);
- dest = (guint8 *) lr.pBits;
- source = GST_BUFFER_DATA (buffer);
-
- if (dest) {
- if (gst_video_format_is_yuv (sink->format)) {
- guint32 fourcc = gst_video_format_to_fourcc (sink->format);
-
- switch (fourcc) {
- case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
- case GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V'):
- case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
- dststride = lr.Pitch;
- srcstride = GST_BUFFER_SIZE (buffer) / sink->height;
- for (i = 0; i < sink->height; ++i)
- memcpy (dest + dststride * i, source + srcstride * i,
- srcstride);
- break;
- case GST_MAKE_FOURCC ('I', '4', '2', '0'):
- case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
- {
- int srcystride, srcvstride, srcustride;
- int dstystride, dstvstride, dstustride;
- int rows;
- guint8 *srcv, *srcu, *dstv, *dstu;
-
- rows = sink->height;
-
- /* Source y, u and v strides */
- srcystride = GST_ROUND_UP_4 (sink->width);
- srcustride = GST_ROUND_UP_8 (sink->width) / 2;
- srcvstride = GST_ROUND_UP_8 (srcystride) / 2;
-
- /* Destination y, u and v strides */
- dstystride = lr.Pitch;
- dstustride = dstystride / 2;
- dstvstride = dstustride;
-
- srcu = source + srcystride * GST_ROUND_UP_2 (rows);
- srcv = srcu + srcustride * GST_ROUND_UP_2 (rows) / 2;
-
- if (fourcc == GST_MAKE_FOURCC ('I', '4', '2', '0')) {
- /* swap u and v planes */
- dstv = dest + dstystride * rows;
- dstu = dstv + dstustride * rows / 2;
- } else {
- dstu = dest + dstystride * rows;
- dstv = dstu + dstustride * rows / 2;
- }
+ drawSurface = sink->d3d_offscreen_surface;
+
+ if (SUCCEEDED (IDirect3DDevice9_BeginScene (sink->d3ddev))) {
+ if (GST_BUFFER_DATA (buffer)) {
+ D3DLOCKED_RECT lr;
+ guint8 *dest, *source;
+ int srcstride, dststride, i;
+
+ IDirect3DSurface9_LockRect (drawSurface, &lr, NULL, 0);
+ dest = (guint8 *) lr.pBits;
+ source = GST_BUFFER_DATA (buffer);
+
+ if (dest) {
+ if (gst_video_format_is_yuv (sink->format)) {
+ guint32 fourcc = gst_video_format_to_fourcc (sink->format);
+
+ switch (fourcc) {
+ case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+ case GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V'):
+ case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+ dststride = lr.Pitch;
+ srcstride = GST_BUFFER_SIZE (buffer) / sink->height;
+ for (i = 0; i < sink->height; ++i)
+ memcpy (dest + dststride * i, source + srcstride * i,
+ srcstride);
+ break;
+ case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+ case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+ {
+ int srcystride, srcvstride, srcustride;
+ int dstystride, dstvstride, dstustride;
+ int rows;
+ guint8 *srcv, *srcu, *dstv, *dstu;
+
+ rows = sink->height;
+
+ /* Source y, u and v strides */
+ srcystride = GST_ROUND_UP_4 (sink->width);
+ srcustride = GST_ROUND_UP_8 (sink->width) / 2;
+ srcvstride = GST_ROUND_UP_8 (srcystride) / 2;
+
+ /* Destination y, u and v strides */
+ dstystride = lr.Pitch;
+ dstustride = dstystride / 2;
+ dstvstride = dstustride;
+
+ srcu = source + srcystride * GST_ROUND_UP_2 (rows);
+ srcv = srcu + srcustride * GST_ROUND_UP_2 (rows) / 2;
+
+ if (fourcc == GST_MAKE_FOURCC ('I', '4', '2', '0')) {
+ /* swap u and v planes */
+ dstv = dest + dstystride * rows;
+ dstu = dstv + dstustride * rows / 2;
+ } else {
+ dstu = dest + dstystride * rows;
+ dstv = dstu + dstustride * rows / 2;
+ }
- for (i = 0; i < rows; ++i) {
- /* Copy the y plane */
- memcpy (dest + dstystride * i, source + srcystride * i,
- srcystride);
- }
+ for (i = 0; i < rows; ++i) {
+ /* Copy the y plane */
+ memcpy (dest + dstystride * i, source + srcystride * i,
+ srcystride);
+ }
- for (i = 0; i < rows / 2; ++i) {
- /* Copy the u plane */
- memcpy (dstu + dstustride * i, srcu + srcustride * i,
- srcustride);
- /* Copy the v plane */
- memcpy (dstv + dstvstride * i, srcv + srcvstride * i,
- srcvstride);
+ for (i = 0; i < rows / 2; ++i) {
+ /* Copy the u plane */
+ memcpy (dstu + dstustride * i, srcu + srcustride * i,
+ srcustride);
+ /* Copy the v plane */
+ memcpy (dstv + dstvstride * i, srcv + srcvstride * i,
+ srcvstride);
+ }
+ break;
+ }
+ case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
+ {
+ guint8 *dst = dest;
+ int component;
+ dststride = lr.Pitch;
+ for (component = 0; component < 2; component++) {
+ const int compHeight =
+ gst_video_format_get_component_height (sink->format,
+ component, sink->height);
+ guint8 *src =
+ source +
+ gst_video_format_get_component_offset (sink->format,
+ component, sink->width, sink->height);
+ srcstride =
+ gst_video_format_get_row_stride (sink->format, component,
+ sink->width);
+ for (i = 0; i < compHeight; i++) {
+ memcpy (dst + dststride * i, src + srcstride * i, srcstride);
}
- break;
+ dst += dststride * compHeight;
}
- default:
- g_assert_not_reached ();
+ break;
}
- } else if (gst_video_format_is_rgb (sink->format)) {
- dststride = lr.Pitch;
- srcstride = GST_BUFFER_SIZE (buffer) / sink->height;
- for (i = 0; i < sink->height; ++i)
- memcpy (dest + dststride * i, source + srcstride * i, srcstride);
+ default:
+ g_assert_not_reached ();
}
+ } else if (gst_video_format_is_rgb (sink->format)) {
+ dststride = lr.Pitch;
+ srcstride = GST_BUFFER_SIZE (buffer) / sink->height;
+ for (i = 0; i < sink->height; ++i)
+ memcpy (dest + dststride * i, source + srcstride * i, srcstride);
}
-
- IDirect3DSurface9_UnlockRect (sink->d3d_offscreen_surface);
- }
- gst_d3dvideosink_stretch (sink, backBuffer);
- IDirect3DDevice9_EndScene (shared.d3ddev);
- }
- /* Swap back and front buffers on video card and present to the user */
- if (FAILED (hr =
- IDirect3DSwapChain9_Present (sink->d3d_swap_chain, NULL, NULL, NULL,
- NULL, 0))) {
- switch (hr) {
- case D3DERR_DEVICELOST:
- case D3DERR_DEVICENOTRESET:
- gst_d3dvideosink_notify_device_lost (sink);
- break;
- default:
- goto wrong_state;
}
+ IDirect3DSurface9_UnlockRect (drawSurface);
}
+ IDirect3DDevice9_EndScene (sink->d3ddev);
}
-
success:
GST_D3DVIDEOSINK_SWAP_CHAIN_UNLOCK (sink);
- GST_D3DVIDEOSINK_SHARED_D3D_DEV_UNLOCK return GST_FLOW_OK;
+ gst_d3dvideosink_refresh (sink);
+ return GST_FLOW_OK;
+ #if 0
wrong_state:
GST_D3DVIDEOSINK_SWAP_CHAIN_UNLOCK (sink);
- GST_D3DVIDEOSINK_SHARED_D3D_DEV_UNLOCK return GST_FLOW_FLUSHING;
- return GST_FLOW_WRONG_STATE;
++ return GST_FLOW_FLUSHING;
/*unexpected:*/
/* GST_D3DVIDEOSINK_SWAP_CHAIN_UNLOCK(sink); */
- /* GST_D3DVIDEOSINK_SHARED_D3D_DEV_UNLOCK */
+ /* */
/* return GST_FLOW_UNEXPECTED; */
+ #endif
error:
GST_D3DVIDEOSINK_SWAP_CHAIN_UNLOCK (sink);
- GST_D3DVIDEOSINK_SHARED_D3D_DEV_UNLOCK return GST_FLOW_ERROR;
+ return GST_FLOW_ERROR;
}
/* Simply redraws the last item on our offscreen surface to the window */