Commit 890f8e0f authored by Thomas Guillem's avatar Thomas Guillem

android: remove get_android_opaque_mutex()

Replace it with a mutex per picture_sys_t. When doing direct rendering, the
picture_sys_t is refcounted between the vout and the decoder.
parent cad45d8a
......@@ -417,7 +417,7 @@ libiomx_plugin_la_LIBADD = $(libomxil_plugin_la_LIBADD)
libmediacodec_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/codec/omxil
libmediacodec_plugin_la_SOURCES = codec/omxil/mediacodec.c codec/omxil/mediacodec.h \
codec/omxil/mediacodec_jni.c codec/omxil/mediacodec_ndk.c codec/omxil/utils.c \
video_chroma/copy.c codec/omxil/android_opaque.c codec/omxil/android_opaque.h \
video_chroma/copy.c
video_output/android/utils.c video_output/android/utils.h
packetizer/h264_nal.c packetizer/h264_nal.h
packetizer/hevc_nal.c packetizer/hevc_nal.h
......
/*****************************************************************************
* android_opaque.c: shared structures between MediaCodec decoder
* and MediaCodec video output
*****************************************************************************
* Copyright (C) 2013 Felix Abecassis
*
* Authors: Felix Abecassis <felix.abecassis@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "android_opaque.h"
vlc_mutex_t* get_android_opaque_mutex()
{
static vlc_mutex_t s_mutex = VLC_STATIC_MUTEX;
return &s_mutex;
}
/*****************************************************************************
* android_opaque.h: shared structures between MediaCodec decoder
* and MediaCodec video output
*****************************************************************************
* Copyright (C) 2013 Felix Abecassis
*
* Authors: Felix Abecassis <felix.abecassis@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef ANDROID_OPAQUE_H_
#define ANDROID_OPAQUE_H_
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
vlc_mutex_t* get_android_opaque_mutex(void);
#endif
......@@ -46,7 +46,6 @@
#include <OMX_Core.h>
#include <OMX_Component.h>
#include "omxil_utils.h"
#include "android_opaque.h"
#include "../../video_output/android/android_window.h"
/* JNI functions to get/set an Android Surface object. */
......@@ -117,7 +116,7 @@ struct decoder_sys_t
size_t i_h264_profile;
ArchitectureSpecificCopyData ascd;
/* stores the inflight picture for each output buffer or NULL */
picture_t** pp_inflight_pictures;
picture_sys_t** pp_inflight_pictures;
unsigned int i_inflight_pictures;
timestamp_fifo_t *timestamp_fifo;
} video;
......@@ -150,7 +149,7 @@ static int Audio_ProcessOutput(decoder_t *, mc_api_out *, picture_t **, block_t
static block_t *DecodeAudio(decoder_t *, block_t **);
static void InvalidateAllPictures(decoder_t *);
static int InsertInflightPicture(decoder_t *, picture_t *, unsigned int );
static void RemoveInflightPictures(decoder_t *);
/*****************************************************************************
* Module descriptor
......@@ -453,10 +452,10 @@ static void StopMediaCodec(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
/* Invalidate all pictures that are currently in flight in order
/* Remove all pictures that are currently in flight in order
* to prevent the vout from using destroyed output buffers. */
if (p_sys->api->b_direct_rendering)
InvalidateAllPictures(p_dec);
RemoveInflightPictures(p_dec);
p_sys->api->stop(p_sys->api);
if (p_dec->fmt_in.i_cat == VIDEO_ES && p_sys->u.video.p_awh)
......@@ -576,6 +575,8 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
p_sys->u.video.timestamp_fifo = timestamp_FifoNew(32);
if (!p_sys->u.video.timestamp_fifo)
goto bailout;
TAB_INIT( p_sys->u.video.i_inflight_pictures,
p_sys->u.video.pp_inflight_pictures );
if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
h264_get_profile_level(&p_dec->fmt_in,
......@@ -673,7 +674,6 @@ static void CloseDecoder(vlc_object_t *p_this)
{
ArchitectureSpecificCopyHooksDestroy(p_sys->u.video.i_pixel_format,
&p_sys->u.video.ascd);
free(p_sys->u.video.pp_inflight_pictures);
if (p_sys->u.video.timestamp_fifo)
timestamp_FifoRelease(p_sys->u.video.timestamp_fifo);
if (p_sys->u.video.p_awh)
......@@ -687,73 +687,48 @@ static void CloseDecoder(vlc_object_t *p_this)
/*****************************************************************************
* vout callbacks
*****************************************************************************/
static void UnlockPicture(picture_t* p_pic, bool b_render)
static void ReleasePicture(decoder_t *p_dec, unsigned i_index, bool b_render)
{
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;
if (!p_picsys->priv.hw.b_valid)
return;
vlc_mutex_lock(get_android_opaque_mutex());
/* Picture might have been invalidated while waiting on the mutex. */
if (!p_picsys->priv.hw.b_valid) {
vlc_mutex_unlock(get_android_opaque_mutex());
return;
}
uint32_t i_index = p_picsys->priv.hw.i_index;
InsertInflightPicture(p_dec, NULL, i_index);
/* Release the MediaCodec buffer. */
p_sys->api->release_out(p_sys->api, i_index, b_render);
p_picsys->priv.hw.b_valid = false;
vlc_mutex_unlock(get_android_opaque_mutex());
}
static void InvalidateAllPictures(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
vlc_mutex_lock(get_android_opaque_mutex());
for (unsigned int i = 0; i < p_sys->u.video.i_inflight_pictures; ++i) {
picture_t *p_pic = p_sys->u.video.pp_inflight_pictures[i];
if (p_pic) {
if (p_pic->p_sys->priv.hw.b_valid)
{
p_sys->api->release_out(p_sys->api, p_pic->p_sys->priv.hw.i_index, false);
p_pic->p_sys->priv.hw.b_valid = false;
}
p_sys->u.video.pp_inflight_pictures[i] = NULL;
}
}
vlc_mutex_unlock(get_android_opaque_mutex());
for (unsigned int i = 0; i < p_sys->u.video.i_inflight_pictures; ++i)
AndroidOpaquePicture_Release(p_sys->u.video.pp_inflight_pictures[i],
false);
}
static int InsertInflightPicture(decoder_t *p_dec, picture_t *p_pic,
unsigned int i_index)
static int InsertInflightPicture(decoder_t *p_dec, picture_sys_t *p_picsys)
{
decoder_sys_t *p_sys = p_dec->p_sys;
if (i_index >= p_sys->u.video.i_inflight_pictures) {
picture_t **pp_pics = realloc(p_sys->u.video.pp_inflight_pictures,
(i_index + 1) * sizeof (picture_t *));
if (!pp_pics)
return -1;
if (i_index - p_sys->u.video.i_inflight_pictures > 0)
memset(&pp_pics[p_sys->u.video.i_inflight_pictures], 0,
(i_index - p_sys->u.video.i_inflight_pictures) * sizeof (picture_t *));
p_sys->u.video.pp_inflight_pictures = pp_pics;
p_sys->u.video.i_inflight_pictures = i_index + 1;
}
p_sys->u.video.pp_inflight_pictures[i_index] = p_pic;
if (!p_picsys->priv.hw.p_dec)
{
p_picsys->priv.hw.p_dec = p_dec;
p_picsys->priv.hw.pf_release = ReleasePicture;
TAB_APPEND_CAST((picture_sys_t **),
p_sys->u.video.i_inflight_pictures,
p_sys->u.video.pp_inflight_pictures,
p_picsys);
} /* else already attached */
return 0;
}
static void RemoveInflightPictures(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
for (unsigned int i = 0; i < p_sys->u.video.i_inflight_pictures; ++i)
AndroidOpaquePicture_DetachDecoder(p_sys->u.video.pp_inflight_pictures[i]);
TAB_CLEAN(p_sys->u.video.i_inflight_pictures,
p_sys->u.video.pp_inflight_pictures);
}
static int Video_ProcessOutput(decoder_t *p_dec, mc_api_out *p_out,
picture_t **pp_out_pic, block_t **pp_out_block)
{
......@@ -816,16 +791,8 @@ static int Video_ProcessOutput(decoder_t *p_dec, mc_api_out *p_out,
if (p_sys->api->b_direct_rendering)
{
picture_sys_t *p_picsys = p_pic->p_sys;
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 = p_out->u.buf.i_index;
p_picsys->priv.hw.b_valid = true;
vlc_mutex_lock(get_android_opaque_mutex());
InsertInflightPicture(p_dec, p_pic, p_out->u.buf.i_index);
vlc_mutex_unlock(get_android_opaque_mutex());
p_pic->p_sys->priv.hw.i_index = p_out->u.buf.i_index;
InsertInflightPicture(p_dec, p_pic->p_sys);
} else {
unsigned int chroma_div;
GetVlcChromaSizes(p_dec->fmt_out.i_codec,
......
......@@ -45,7 +45,6 @@
#if defined(USE_IOMX)
#include <dlfcn.h>
#include <jni.h>
#include "android_opaque.h"
#include "../../video_output/android/android_window.h"
#endif
......@@ -91,7 +90,7 @@ static OMX_ERRORTYPE OmxFillBufferDone( OMX_HANDLETYPE, OMX_PTR,
#if defined(USE_IOMX)
static void *DequeueThread( void *data );
static void UnlockPicture( picture_t* p_pic, bool b_render );
static void ReleasePicture( decoder_t *p_dec, unsigned int i_index, 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 );
......@@ -1611,11 +1610,8 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
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
......@@ -2240,7 +2236,7 @@ static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
goto error;
p_port->p_hwbuf->inflight_picture = calloc( p_port->p_hwbuf->i_buffers,
sizeof(picture_t*) );
sizeof(picture_sys_t*) );
if( !p_port->p_hwbuf->inflight_picture )
goto error;
......@@ -2375,19 +2371,10 @@ static int HwBuffer_Stop( decoder_t *p_dec, OmxPort *p_port )
/* invalidate and release all inflight pictures */
if( p_port->p_hwbuf->inflight_picture ) {
for( unsigned int i = 0; i < p_port->i_buffers; ++i ) {
picture_t *p_pic = p_port->p_hwbuf->inflight_picture[i];
if( p_pic ) {
picture_sys_t *p_picsys = p_pic->p_sys;
if( p_picsys ) {
void *p_handle = p_port->pp_buffers[p_picsys->priv.hw.i_index]->pBuffer;
if( p_handle )
{
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->priv.hw.b_valid = false;
}
picture_sys_t *p_picsys = p_port->p_hwbuf->inflight_picture[i];
if( p_picsys )
{
AndroidOpaquePicture_DetachDecoder(p_picsys);
p_port->p_hwbuf->inflight_picture[i] = NULL;
}
}
......@@ -2454,13 +2441,11 @@ static int HwBuffer_GetPic( decoder_t *p_dec, OmxPort *p_port,
p_pic->date = FromOmxTicks( p_header->nTimeStamp );
p_picsys = p_pic->p_sys;
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;
p_picsys->priv.hw.p_dec = p_dec;
p_picsys->priv.hw.pf_release = ReleasePicture;
p_port->p_hwbuf->inflight_picture[i_index] = p_pic;
p_port->p_hwbuf->inflight_picture[i_index] = p_picsys;
*pp_pic = p_pic;
OMX_FIFO_GET( &p_port->fifo, p_header );
......@@ -2559,25 +2544,15 @@ static void *DequeueThread( void *data )
/*****************************************************************************
* vout callbacks
*****************************************************************************/
static void UnlockPicture( picture_t* p_pic, bool b_render )
static void ReleasePicture( decoder_t *p_dec, unsigned int i_index,
bool b_render )
{
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;
HWBUFFER_LOCK( p_port );
if( !p_picsys->priv.hw.b_valid ) return;
/* Picture might have been invalidated while waiting on the mutex. */
if (!p_picsys->priv.hw.b_valid) {
HWBUFFER_UNLOCK();
return;
}
p_handle = p_port->pp_buffers[p_picsys->priv.hw.i_index]->pBuffer;
p_handle = p_port->pp_buffers[i_index]->pBuffer;
OMX_DBG( "DisplayBuffer: %s %p",
b_render ? "render" : "cancel", p_handle );
......@@ -2593,14 +2568,10 @@ static void UnlockPicture( picture_t* p_pic, bool b_render )
else
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 );
HwBuffer_ChangeState( p_dec, p_port, i_index, BUF_STATE_NOT_OWNED );
HWBUFFER_BROADCAST( p_port );
p_port->p_hwbuf->inflight_picture[p_picsys->priv.hw.i_index] = NULL;
end:
p_picsys->priv.hw.b_valid = false;
p_picsys->priv.hw.i_index = -1;
HWBUFFER_UNLOCK( p_port );
}
......
......@@ -67,7 +67,7 @@ typedef struct HwBuffer
bool b_run;
vlc_mutex_t lock;
vlc_cond_t wait;
picture_t** inflight_picture; /**< stores the inflight picture for each output buffer or NULL */
picture_sys_t** inflight_picture; /**< stores the inflight picture for each output buffer or NULL */
unsigned int i_buffers;
void **pp_handles;
......
......@@ -176,7 +176,26 @@ static int UpdateWindowSize(vout_display_sys_t *sys, video_format_t *p_fmt,
return 0;
}
static picture_t *PictureAlloc(vout_display_sys_t *sys, video_format_t *fmt)
static void AndroidOpaquePicture_DetachVout(picture_t *p_pic)
{
picture_sys_t *p_picsys = p_pic->p_sys;
vlc_mutex_lock(&p_picsys->priv.hw.lock);
p_pic->p_sys->p_vd_sys = NULL;
/* Release p_picsys if references from VOUT and from decoder are NULL */
if (!p_picsys->p_vd_sys && !p_picsys->priv.hw.p_dec)
{
vlc_mutex_unlock(&p_picsys->priv.hw.lock);
vlc_mutex_destroy(&p_picsys->priv.hw.lock);
free(p_picsys);
}
else
vlc_mutex_unlock(&p_picsys->priv.hw.lock);
free(p_pic);
}
static picture_t *PictureAlloc(vout_display_sys_t *sys, video_format_t *fmt,
bool b_opaque)
{
picture_t *p_pic;
picture_resource_t rsc;
......@@ -188,7 +207,14 @@ static picture_t *PictureAlloc(vout_display_sys_t *sys, video_format_t *fmt)
p_picsys->p_vd_sys = sys;
memset(&rsc, 0, sizeof(picture_resource_t));
rsc.p_sys = p_picsys,
rsc.p_sys = p_picsys;
if (b_opaque)
{
p_picsys->priv.hw.i_index = -1;
vlc_mutex_init(&p_picsys->priv.hw.lock);
rsc.pf_destroy = AndroidOpaquePicture_DetachVout;
}
p_pic = picture_NewFromResource(fmt, &rsc);
if (!p_pic)
......@@ -506,7 +532,7 @@ static int AndroidWindow_Setup(vout_display_sys_t *sys,
if (!p_window->b_opaque) {
int align_pixels;
picture_t *p_pic = PictureAlloc(sys, &p_window->fmt);
picture_t *p_pic = PictureAlloc(sys, &p_window->fmt, false);
// For RGB (32 or 16) we need to align on 8 or 4 pixels, 16 pixels for YUV
align_pixels = (16 / p_pic->p[0].i_pixel_pitch) - 1;
......@@ -751,37 +777,30 @@ static void Close(vlc_object_t *p_this)
free(sys);
}
static int DefaultLockPicture(picture_t *p_pic)
{
picture_sys_t *p_picsys = p_pic->p_sys;
vout_display_sys_t *sys = p_picsys->p_vd_sys;
return AndroidWindow_LockPicture(sys, sys->p_window, p_pic);
}
static void DefaultUnlockPicture(picture_t *p_pic, bool b_render)
{
picture_sys_t *p_picsys = p_pic->p_sys;
vout_display_sys_t *sys = p_picsys->p_vd_sys;
AndroidWindow_UnlockPicture(sys, sys->p_window, p_pic, b_render);
}
static void UnlockPicture(picture_t *p_pic, bool b_render)
{
picture_sys_t *p_picsys = p_pic->p_sys;
vout_display_sys_t *sys = p_picsys->p_vd_sys;
if (p_picsys->b_locked && p_picsys->pf_unlock_pic)
p_picsys->pf_unlock_pic(p_pic, b_render);
p_picsys->b_locked = false;
if (p_picsys->b_locked)
{
if (sys->p_window->b_opaque)
AndroidOpaquePicture_Release(p_picsys, b_render);
else
AndroidWindow_UnlockPicture(sys, sys->p_window, p_pic, b_render);
p_picsys->b_locked = false;
}
}
static int PoolLockPicture(picture_t *p_pic)
{
picture_sys_t *p_picsys = p_pic->p_sys;
vout_display_sys_t *sys = p_picsys->p_vd_sys;
if (p_picsys->pf_lock_pic && p_picsys->pf_lock_pic(p_pic) != 0)
if (!sys->p_window->b_opaque
&& AndroidWindow_LockPicture(sys, sys->p_window, p_pic) != 0)
return -1;
p_picsys->b_locked = true;
return 0;
}
......@@ -811,13 +830,10 @@ static picture_pool_t *PoolAlloc(vout_display_t *vd, unsigned requested_count)
for (i = 0; i < requested_count; i++)
{
picture_t *p_pic = PictureAlloc(sys, &sys->p_window->fmt);
picture_t *p_pic = PictureAlloc(sys, &sys->p_window->fmt,
sys->p_window->b_opaque);
if (!p_pic)
goto error;
if (!sys->p_window->b_opaque) {
p_pic->p_sys->pf_lock_pic = DefaultLockPicture;
p_pic->p_sys->pf_unlock_pic = DefaultUnlockPicture;
}
pp_pics[i] = p_pic;
}
......@@ -990,7 +1006,7 @@ static void Prepare(vout_display_t *vd, picture_t *picture,
if (!sys->p_sub_pic
&& AndroidWindow_Setup(sys, sys->p_sub_window, 1) == 0)
sys->p_sub_pic = PictureAlloc(sys, &sys->p_sub_window->fmt);
sys->p_sub_pic = PictureAlloc(sys, &sys->p_sub_window->fmt, false);
if (!sys->p_spu_blend && sys->p_sub_pic)
sys->p_spu_blend = filter_NewBlend(VLC_OBJECT(vd),
&sys->p_sub_pic->format);
......
......@@ -31,6 +31,7 @@
# include "config.h"
#endif
#include <assert.h>
#include <vlc_common.h>
#include <vlc_vout_display.h>
#include <android/native_window.h>
......@@ -39,14 +40,13 @@ struct picture_sys_t
{
vout_display_sys_t *p_vd_sys;
int (*pf_lock_pic)(picture_t *);
void (*pf_unlock_pic)(picture_t *, bool b_render);
union {
struct {
vlc_mutex_t lock;
decoder_t *p_dec;
uint32_t i_index;
bool b_valid;
int i_index;
void (*pf_release)(decoder_t *p_dec, unsigned int i_index,
bool b_render);
} hw;
struct {
void *p_handle;
......@@ -56,4 +56,44 @@ struct picture_sys_t
bool b_locked;
};
static inline void
AndroidOpaquePicture_DetachDecoder(picture_sys_t *p_picsys)
{
vlc_mutex_lock(&p_picsys->priv.hw.lock);
if (p_picsys->priv.hw.i_index >= 0)
{
assert(p_picsys->priv.hw.pf_release && p_picsys->priv.hw.p_dec);
p_picsys->priv.hw.pf_release(p_picsys->priv.hw.p_dec,
(unsigned int) p_picsys->priv.hw.i_index,
false);
p_picsys->priv.hw.i_index = -1;
}
p_picsys->priv.hw.pf_release = NULL;
p_picsys->priv.hw.p_dec = NULL;
/* Release p_picsys if references from VOUT and from decoder are NULL */
if (!p_picsys->p_vd_sys && !p_picsys->priv.hw.p_dec)
{
vlc_mutex_unlock(&p_picsys->priv.hw.lock);
vlc_mutex_destroy(&p_picsys->priv.hw.lock);
free(p_picsys);
}
else
vlc_mutex_unlock(&p_picsys->priv.hw.lock);
}
static inline void
AndroidOpaquePicture_Release(picture_sys_t *p_picsys, bool b_render)
{
vlc_mutex_lock(&p_picsys->priv.hw.lock);
if (p_picsys->priv.hw.i_index >= 0)
{
assert(p_picsys->priv.hw.pf_release && p_picsys->priv.hw.p_dec);
p_picsys->priv.hw.pf_release(p_picsys->priv.hw.p_dec,
(unsigned int) p_picsys->priv.hw.i_index,
b_render);
p_picsys->priv.hw.i_index = -1;
}
vlc_mutex_unlock(&p_picsys->priv.hw.lock);
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment