#include <vlc_block_helper.h>
#include <vlc_cpu.h>
#include "../h264_nal.h"
+#include "../hevc_nal.h"
#include "omxil.h"
#include "omxil_core.h"
#include <dlfcn.h>
#include <jni.h>
#include "android_opaque.h"
+#include "../../video_output/android/android_window.h"
#endif
#ifndef NDEBUG
#if defined(USE_IOMX)
/* JNI functions to get/set an Android Surface object. */
-extern JavaVM *myVm;
+#define THREAD_NAME "omxil"
+extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
+extern void jni_detach_thread();
extern jobject jni_LockAndGetAndroidJavaSurface();
extern void jni_UnlockAndroidSurface();
-extern void jni_SetAndroidSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den);
extern bool jni_IsVideoPlayerActivityCreated();
#endif
#if defined(USE_IOMX)
static void *DequeueThread( void *data );
-static void DisplayCallback( picture_sys_t* p_picsys );
-static void UnlockCallback( picture_sys_t* p_picsys );
+static void UnlockPicture( picture_t* p_pic, bool b_render );
static void HwBuffer_Init( decoder_t *p_dec, OmxPort *p_port );
static void HwBuffer_Destroy( decoder_t *p_dec, OmxPort *p_port );
static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port );
* enable it only via the --codec iomx command line parameter when
* wanted. */
set_capability( "decoder", 0 )
- add_bool(CFG_PREFIX "dr", false,
+ add_bool(CFG_PREFIX "dr", true,
DIRECTRENDERING_TEXT, DIRECTRENDERING_LONGTEXT, true)
#else
set_capability( "decoder", 80 )
p_port->i_port_index, 0,
p_port->definition.nBufferSize, (void*)1);
OMX_DBG( "OMX_UseBuffer(%d) %p, %p", def->eDir,
- p_port->pp_buffers[i], p_port->pp_buffers[i]->pBuffer );
+ p_port->pp_buffers[i], p_port->pp_buffers[i] ?
+ p_port->pp_buffers[i]->pBuffer : NULL );
}
else
{
p_port->i_port_index, 0,
p_port->definition.nBufferSize);
OMX_DBG( "OMX_AllocateBuffer(%d) %p, %p", def->eDir,
- p_port->pp_buffers[i], p_port->pp_buffers[i]->pBuffer );
+ p_port->pp_buffers[i], p_port->pp_buffers[i] ?
+ p_port->pp_buffers[i]->pBuffer : NULL );
}
if(omx_error != OMX_ErrorNone)
if( p_buffer )
{
if (p_buffer->pAppPrivate != NULL)
- decoder_DeletePicture( p_dec, p_buffer->pAppPrivate );
+ picture_Release( p_buffer->pAppPrivate );
omx_error = OMX_FreeBuffer( p_port->omx_handle,
p_port->i_port_index, p_buffer );
p_header->pBuffer, p_header->nAllocLen,
(uint32_t*) &p_header->nFilledLen, NULL );
}
+ else if( p_dec->fmt_in.i_codec == VLC_CODEC_HEVC && !p_sys->in.b_direct )
+ {
+ p_header->nFilledLen = 0;
+ convert_hevc_nal_units( p_dec, p_dec->fmt_in.p_extra,
+ p_dec->fmt_in.i_extra,
+ p_header->pBuffer, p_header->nAllocLen,
+ (uint32_t*) &p_header->nFilledLen,
+ &p_sys->i_nal_size_length );
+ }
else if(p_sys->in.b_direct)
{
p_header->pOutputPortPrivate = p_header->pBuffer;
block_t *p_block = *pp_block;
/* Send the input buffer to the component */
- OMX_FIFO_GET_TIMEOUT(&p_port->fifo, p_header, 200000);
+ OMX_FIFO_GET_TIMEOUT(&p_port->fifo, p_header, 10000);
if (p_header && p_header->nFlags & SENTINEL_FLAG) {
free(p_header);
picture_t *p_pic = NULL;
OMX_ERRORTYPE omx_error;
unsigned int i;
- bool b_reconfig;
block_t *p_block;
if( !pp_block || !*pp_block )
if( DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
goto error;
- if( DecodeVideoInput( p_dec, &p_sys->in, pp_block, 0, &b_reconfig ) != 0 )
- goto error;
+ /* Loop as long as we haven't either got an input buffer (and cleared
+ * *pp_block) or got an output picture */
+ int max_polling_attempts = 100;
+ int attempts = 0;
+ while( *pp_block && !p_pic ) {
+ bool b_reconfig = false;
- /* If we don't have a p_pic from the first try. Try again */
- if( !b_reconfig && !p_pic &&
- DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
- goto error;
+ if( DecodeVideoInput( p_dec, &p_sys->in, pp_block, 0, &b_reconfig ) != 0 )
+ goto error;
- /* Handle the PortSettingsChanged events */
- for(i = 0; i < p_sys->ports; i++)
- {
- OmxPort *p_port = &p_sys->p_ports[i];
- if(p_port->b_reconfigure)
+ /* If we don't have a p_pic from the first try. Try again */
+ if( !b_reconfig && !p_pic &&
+ DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
+ goto error;
+
+ /* Handle the PortSettingsChanged events */
+ for(i = 0; i < p_sys->ports; i++)
{
- omx_error = PortReconfigure(p_dec, p_port);
- p_port->b_reconfigure = 0;
- CHECK_ERROR(omx_error, "PortReconfigure failed");
+ OmxPort *p_port = &p_sys->p_ports[i];
+ if(p_port->b_reconfigure)
+ {
+ omx_error = PortReconfigure(p_dec, p_port);
+ p_port->b_reconfigure = 0;
+ CHECK_ERROR(omx_error, "PortReconfigure failed");
+ }
+ if(p_port->b_update_def)
+ {
+ omx_error = GetPortDefinition(p_dec, p_port, p_port->p_fmt);
+ p_port->b_update_def = 0;
+ CHECK_ERROR(omx_error, "GetPortDefinition failed");
+ }
}
- if(p_port->b_update_def)
- {
- omx_error = GetPortDefinition(p_dec, p_port, p_port->p_fmt);
- p_port->b_update_def = 0;
- CHECK_ERROR(omx_error, "GetPortDefinition failed");
+
+ attempts++;
+ /* With opaque DR the output buffers are released by the
+ vout therefore we implement a timeout for polling in
+ order to avoid being indefinitely stalled in this loop, if
+ playback is paused. */
+ if( p_sys->out.p_hwbuf && attempts == max_polling_attempts ) {
+#ifdef USE_IOMX
+ picture_t *invalid_picture = decoder_NewPicture(p_dec);
+ if (invalid_picture) {
+ invalid_picture->date = VLC_TS_INVALID;
+ picture_sys_t *p_picsys = invalid_picture->p_sys;
+ p_picsys->pf_lock_pic = NULL;
+ p_picsys->pf_unlock_pic = NULL;
+ p_picsys->priv.hw.p_dec = NULL;
+ p_picsys->priv.hw.i_index = -1;
+ p_picsys->priv.hw.b_valid = false;
+ } else {
+ /* If we cannot return a picture we must free the
+ block since the decoder will proceed with the
+ next block. */
+ block_Release(p_block);
+ *pp_block = NULL;
+ }
+ return invalid_picture;
+#endif
}
}
msg_Dbg( p_dec, "HwBuffer_Init");
if( !(pf_enable_graphic_buffers && pf_get_graphic_buffer_usage &&
- pf_omx_hwbuffer_connect && pf_omx_hwbuffer_disconnect &&
- pf_omx_hwbuffer_setup && pf_omx_hwbuffer_setcrop &&
- pf_omx_hwbuffer_dequeue && pf_omx_hwbuffer_queue &&
- pf_omx_hwbuffer_cancel &&
+ pf_get_hal_format &&
((OMX_COMPONENTTYPE*)p_port->omx_handle)->UseBuffer) )
{
msg_Warn( p_dec, "direct output port enabled but can't find "
msg_Warn( p_dec, "LoadNativeWindowAPI failed" );
goto error;
}
+ if( LoadNativeWindowPrivAPI( &p_port->p_hwbuf->anwpriv ) != 0 )
+ {
+ msg_Warn( p_dec, "LoadNativeWindowPrivAPI failed" );
+ goto error;
+ }
surf = jni_LockAndGetAndroidJavaSurface();
if( !surf ) {
goto error;
}
- (*myVm)->AttachCurrentThread( myVm, &p_env, NULL );
+ jni_attach_thread( &p_env, THREAD_NAME );
p_port->p_hwbuf->window = p_port->p_hwbuf->native_window.winFromSurface( p_env, surf );
- (*myVm)->DetachCurrentThread( myVm );
+ jni_detach_thread();
jni_UnlockAndroidSurface();
if( !p_port->p_hwbuf->window ) {
msg_Warn( p_dec, "winFromSurface failed" );
goto error;
}
- pf_omx_hwbuffer_connect( p_port->p_hwbuf->window );
+ p_port->p_hwbuf->window_priv =
+ p_port->p_hwbuf->anwpriv.connect( p_port->p_hwbuf->window );
+ if( !p_port->p_hwbuf->window_priv ) {
+ msg_Warn( p_dec, "connect failed" );
+ p_port->p_hwbuf->native_window.winRelease( p_port->p_hwbuf->window );
+ p_port->p_hwbuf->window = NULL;
+ goto error;
+ }
omx_error = pf_enable_graphic_buffers( p_port->omx_handle,
p_port->i_port_index, OMX_TRUE );
HwBuffer_Stop( p_dec, p_port );
HwBuffer_FreeBuffers( p_dec, p_port );
HwBuffer_Join( p_dec, p_port );
- pf_omx_hwbuffer_disconnect( p_port->p_hwbuf->window );
+ p_port->p_hwbuf->anwpriv.disconnect( p_port->p_hwbuf->window_priv );
pf_enable_graphic_buffers( p_port->omx_handle,
p_port->i_port_index, OMX_FALSE );
p_port->p_hwbuf->native_window.winRelease( p_port->p_hwbuf->window );
decoder_sys_t *p_sys = p_dec->p_sys;
OMX_PARAM_PORTDEFINITIONTYPE *def = &p_port->definition;
unsigned int min_undequeued = 0;
- unsigned int num_frames = def->nBufferCountMin;
unsigned int i = 0;
int colorFormat = def->format.video.eColorFormat;
OMX_ERRORTYPE omx_error;
if( !p_port->p_hwbuf )
return 0;
- if( !strncmp( p_sys->psz_component, "OMX.SEC.", 8 ) ) {
- switch( colorFormat ) {
- case OMX_COLOR_FormatYUV420SemiPlanar:
- colorFormat = 0x105; // HAL_PIXEL_FORMAT_YCbCr_420_SP
- break;
- case OMX_COLOR_FormatYUV420Planar:
- colorFormat = 0x101; // HAL_PIXEL_FORMAT_YCbCr_420_P
- break;
- }
+ omx_error = pf_get_hal_format( p_sys->psz_component, &colorFormat );
+ if( omx_error != OMX_ErrorNone )
+ {
+ msg_Warn( p_dec, "pf_get_hal_format failed (Not fatal)" );
}
omx_error = pf_get_graphic_buffer_usage( p_port->omx_handle,
i_hw_usage = 0;
}
- if( pf_omx_hwbuffer_setup( p_port->p_hwbuf->window,
- def->format.video.nFrameWidth,
- def->format.video.nFrameHeight,
- colorFormat,
- (int) i_hw_usage,
- &num_frames, &min_undequeued) != 0 )
+ if( p_port->p_fmt->video.orientation != ORIENT_NORMAL )
+ {
+ int i_angle;
+
+ switch( p_port->p_fmt->video.orientation )
+ {
+ case ORIENT_ROTATED_90:
+ i_angle = 90;
+ break;
+ case ORIENT_ROTATED_180:
+ i_angle = 180;
+ break;
+ case ORIENT_ROTATED_270:
+ i_angle = 270;
+ break;
+ default:
+ i_angle = 0;
+ }
+ p_port->p_hwbuf->anwpriv.setOrientation( p_port->p_hwbuf->window_priv,
+ i_angle );
+ }
+
+ if( p_port->p_hwbuf->anwpriv.setUsage( p_port->p_hwbuf->window_priv,
+ true, (int) i_hw_usage ) != 0 )
{
- msg_Err( p_dec, "can't setup OMXHWBuffer" );
+ msg_Err( p_dec, "can't set usage" );
+ goto error;
+ }
+ if( p_port->p_hwbuf->anwpriv.setBuffersGeometry( p_port->p_hwbuf->window_priv,
+ def->format.video.nFrameWidth,
+ def->format.video.nFrameHeight,
+ colorFormat ) != 0 )
+ {
+ msg_Err( p_dec, "can't set buffers geometry" );
goto error;
}
- if( num_frames != p_port->definition.nBufferCountActual )
+ if( p_port->p_hwbuf->anwpriv.getMinUndequeued( p_port->p_hwbuf->window_priv,
+ &min_undequeued ) != 0 )
{
+ msg_Err( p_dec, "can't get min_undequeued" );
+ goto error;
+ }
+
+ if( def->nBufferCountActual < def->nBufferCountMin + min_undequeued )
+ {
+ unsigned int new_frames_num = def->nBufferCountMin + min_undequeued;
+
OMX_DBG( "AllocateBuffers: video out wants more frames: %lu vs %u",
- p_port->definition.nBufferCountActual, num_frames);
+ p_port->definition.nBufferCountActual, new_frames_num );
- p_port->definition.nBufferCountActual = num_frames;
+ p_port->definition.nBufferCountActual = new_frames_num;
omx_error = OMX_SetParameter( p_dec->p_sys->omx_handle,
OMX_IndexParamPortDefinition,
&p_port->definition );
omx_error, ErrorToString(omx_error) );
}
- jni_SetAndroidSurfaceSize( def->format.video.nFrameWidth,
- def->format.video.nFrameHeight,
- def->format.video.nFrameWidth,
- def->format.video.nFrameHeight,
- p_dec->fmt_out.video.i_sar_num,
- p_dec->fmt_out.video.i_sar_den );
+ if( p_port->p_hwbuf->anwpriv.setBufferCount( p_port->p_hwbuf->window_priv,
+ def->nBufferCountActual ) != 0 )
+ {
+ msg_Err( p_dec, "can't set buffer_count" );
+ goto error;
+ }
p_port->p_hwbuf->i_buffers = p_port->definition.nBufferCountActual;
p_port->p_hwbuf->i_max_owned = p_port->p_hwbuf->i_buffers - min_undequeued;
{
void *p_handle = NULL;
- if( pf_omx_hwbuffer_dequeue( p_port->p_hwbuf->window, &p_handle ) != 0 )
+ if( p_port->p_hwbuf->anwpriv.dequeue( p_port->p_hwbuf->window_priv,
+ &p_handle ) != 0 )
{
msg_Err( p_dec, "OMXHWBuffer_dequeue Fail" );
goto error;
for(; i < p_port->p_hwbuf->i_buffers; i++)
{
OMX_DBG( "canceling buffer(%d)", i );
- pf_omx_hwbuffer_cancel( p_port->p_hwbuf->window,
- p_port->p_hwbuf->pp_handles[i] );
+ p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv,
+ p_port->p_hwbuf->pp_handles[i] );
}
return 0;
if( p_handle && p_port->p_hwbuf->i_states[i] == BUF_STATE_OWNED )
{
- pf_omx_hwbuffer_cancel( p_port->p_hwbuf->window, p_handle );
+ p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
HwBuffer_ChangeState( p_dec, p_port, i, BUF_STATE_NOT_OWNED );
}
}
if( p_header && p_port->p_hwbuf->i_states[i] == BUF_STATE_OWNED )
{
+ if( p_port->p_hwbuf->anwpriv.lock( p_port->p_hwbuf->window_priv,
+ p_header->pBuffer ) != 0 )
+ {
+ msg_Err( p_dec, "lock failed" );
+ HWBUFFER_UNLOCK();
+ return -1;
+ }
OMX_DBG( "FillThisBuffer %p, %p", p_header, p_header->pBuffer );
OMX_FillThisBuffer( p_port->omx_handle, p_header );
}
/*****************************************************************************
* HwBuffer_Stop: stop DequeueThread and invalidate all pictures that are sent
- * to vlc core. The thread can be stuck in pf_omx_hwbuffer_dequeue, so don't
+ * to vlc core. The thread can be stuck in dequeue, so don't
* join it now since it can be unblocked later by HwBuffer_FreeBuffers.
*****************************************************************************/
static int HwBuffer_Stop( decoder_t *p_dec, OmxPort *p_port )
if( p_pic ) {
picture_sys_t *p_picsys = p_pic->p_sys;
if( p_picsys ) {
- void *p_handle = p_port->pp_buffers[p_picsys->i_index]->pBuffer;
+ void *p_handle = p_port->pp_buffers[p_picsys->priv.hw.i_index]->pBuffer;
if( p_handle )
{
- pf_omx_hwbuffer_cancel( p_port->p_hwbuf->window, p_handle );
- HwBuffer_ChangeState( p_dec, p_port, p_picsys->i_index,
+ p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
+ HwBuffer_ChangeState( p_dec, p_port, p_picsys->priv.hw.i_index,
BUF_STATE_NOT_OWNED );
}
- p_picsys->b_valid = false;
+ p_picsys->priv.hw.b_valid = false;
}
p_port->p_hwbuf->inflight_picture[i] = NULL;
}
p_pic->date = FromOmxTicks( p_header->nTimeStamp );
p_picsys = p_pic->p_sys;
- p_picsys->pf_display_callback = DisplayCallback;
- p_picsys->pf_unlock_callback = UnlockCallback;
- p_picsys->p_dec = p_dec;
- p_picsys->i_index = i_index;
- p_picsys->b_valid = true;
+ p_picsys->pf_lock_pic = NULL;
+ p_picsys->pf_unlock_pic = UnlockPicture;
+ p_picsys->priv.hw.p_dec = p_dec;
+ p_picsys->priv.hw.i_index = i_index;
+ p_picsys->priv.hw.b_valid = true;
HWBUFFER_LOCK();
p_port->p_hwbuf->inflight_picture[i_index] = p_pic;
{
VLC_UNUSED( p_dec );
- pf_omx_hwbuffer_setcrop( p_port->p_hwbuf->window,
- p_rect->nLeft, p_rect->nTop,
- p_rect->nWidth, p_rect->nHeight );
+ p_port->p_hwbuf->anwpriv.setCrop( p_port->p_hwbuf->window_priv,
+ p_rect->nLeft, p_rect->nTop,
+ p_rect->nWidth, p_rect->nHeight );
}
/*****************************************************************************
/* The thread can be stuck here. It shouldn't happen since we make sure
* we call the dequeue function if there is at least one buffer
* available. */
- err = pf_omx_hwbuffer_dequeue( p_port->p_hwbuf->window, &p_handle );
+ err = p_port->p_hwbuf->anwpriv.dequeue( p_port->p_hwbuf->window_priv, &p_handle );
+ if( err == 0 )
+ err = p_port->p_hwbuf->anwpriv.lock( p_port->p_hwbuf->window_priv, p_handle );
HWBUFFER_LOCK();
if( !p_port->p_hwbuf->b_run )
{
- pf_omx_hwbuffer_cancel( p_port->p_hwbuf->window, p_handle );
+ p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
continue;
}
}
if( i_index == -1 )
{
- msg_Err( p_dec, "pf_omx_hwbuffer_dequeue returned unknown handle" );
+ msg_Err( p_dec, "p_port->p_hwbuf->anwpriv.dequeue returned unknown handle" );
continue;
}
/*****************************************************************************
* vout callbacks
*****************************************************************************/
-static void DisplayBuffer( picture_sys_t* p_picsys, bool b_render )
+static void UnlockPicture( picture_t* p_pic, bool b_render )
{
- decoder_t *p_dec = p_picsys->p_dec;
+ picture_sys_t *p_picsys = p_pic->p_sys;
+ decoder_t *p_dec = p_picsys->priv.hw.p_dec;
decoder_sys_t *p_sys = p_dec->p_sys;
OmxPort *p_port = &p_sys->out;
void *p_handle;
- if( !p_picsys->b_valid ) return;
+ if( !p_picsys->priv.hw.b_valid ) return;
HWBUFFER_LOCK();
/* Picture might have been invalidated while waiting on the mutex. */
- if (!p_picsys->b_valid) {
+ if (!p_picsys->priv.hw.b_valid) {
HWBUFFER_UNLOCK();
return;
}
- p_handle = p_port->pp_buffers[p_picsys->i_index]->pBuffer;
+ p_handle = p_port->pp_buffers[p_picsys->priv.hw.i_index]->pBuffer;
OMX_DBG( "DisplayBuffer: %s %p",
b_render ? "render" : "cancel", p_handle );
}
if( b_render )
- pf_omx_hwbuffer_queue( p_port->p_hwbuf->window, p_handle );
+ p_port->p_hwbuf->anwpriv.queue( p_port->p_hwbuf->window_priv, p_handle );
else
- pf_omx_hwbuffer_cancel( p_port->p_hwbuf->window, p_handle );
+ p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
- HwBuffer_ChangeState( p_dec, p_port, p_picsys->i_index, BUF_STATE_NOT_OWNED );
+ HwBuffer_ChangeState( p_dec, p_port, p_picsys->priv.hw.i_index, BUF_STATE_NOT_OWNED );
HWBUFFER_BROADCAST( p_port );
- p_port->p_hwbuf->inflight_picture[p_picsys->i_index] = NULL;
+ p_port->p_hwbuf->inflight_picture[p_picsys->priv.hw.i_index] = NULL;
end:
- p_picsys->b_valid = false;
- p_picsys->i_index = -1;
+ p_picsys->priv.hw.b_valid = false;
+ p_picsys->priv.hw.i_index = -1;
HWBUFFER_UNLOCK();
}
-static void UnlockCallback( picture_sys_t* p_picsys )
-{
- DisplayBuffer( p_picsys, false );
-}
-
-static void DisplayCallback( picture_sys_t* p_picsys )
-{
- DisplayBuffer( p_picsys, true );
-}
-
#endif // USE_IOMX