mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-14 20:00:01 +01:00
add some FIXMEs, refactor, fix av log level, fix garbage in video
This commit is contained in:
@@ -318,6 +318,29 @@ int avhelper_recv_frame_packet( void *decoder )
|
||||
return -1; // error
|
||||
}
|
||||
|
||||
int avhelper_decode_video_buffer( void *ptr, uint8_t *data, int len )
|
||||
{
|
||||
int got_picture = 0;
|
||||
el_decoder_t * e = (el_decoder_t*) ptr;
|
||||
|
||||
avcodec_decode_video( e->codec_ctx, e->frames[e->frame_index], &got_picture, data, len );
|
||||
|
||||
//avhelper_frame_unref(e->frames[e->frame_index]);
|
||||
|
||||
if(got_picture) {
|
||||
e->frameinfo[e->frame_index] = 1; /* we have a full picture at this index */
|
||||
e->frame_index = (e->frame_index + 1) % 2; /* use next available buffer */
|
||||
e->frameinfo[e->frame_index] = 0; /* and clear the information */
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
e->frameinfo[e->frame_index] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int avhelper_recv_decode( void *decoder, int *got_picture )
|
||||
{
|
||||
el_decoder_t *x = (el_decoder_t*) decoder;
|
||||
@@ -501,7 +524,7 @@ further:
|
||||
veejay_memset( &(x->packets[0]), 0, sizeof(AVPacket));
|
||||
AVFrame *f = avhelper_alloc_frame();
|
||||
x->output = yuv_yuv_template( NULL,NULL,NULL, wid, hei, dst_pixfmt );
|
||||
x->spvf = ( (double) x->codec_ctx->framerate.den ) / ( (double) x->codec_ctx->framerate.num);
|
||||
x->spvf = ( (double) x->codec_ctx->framerate.den ) / ( (double) x->codec_ctx->framerate.num);
|
||||
|
||||
int got_picture = 0;
|
||||
while(1) {
|
||||
|
||||
@@ -66,6 +66,8 @@ int avhelper_recv_decode( void *decoder, int *got_picture );
|
||||
|
||||
int avhelper_recv_frame_packet( void *decoder );
|
||||
|
||||
int avhelper_decode_video_buffer( void *ptr, uint8_t *data, int len );
|
||||
|
||||
double avhelper_get_spvf( void *decoder );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -415,11 +415,9 @@ int vj_avcodec_init( int pixel_format, int verbose)
|
||||
|
||||
char *av_log_setting = getenv("VEEJAY_AV_LOG");
|
||||
if(av_log_setting != NULL) {
|
||||
int enabled = atoi(av_log_setting);
|
||||
if(enabled) {
|
||||
veejay_msg(VEEJAY_MSG_DEBUG, "FFMpeg Log is enabled");
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
}
|
||||
int level = atoi(av_log_setting);
|
||||
veejay_msg(VEEJAY_MSG_DEBUG, "ffmpeg/libav log level set to %d", level);
|
||||
av_log_set_level(level);
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_BUILD < 5400
|
||||
|
||||
@@ -55,6 +55,10 @@ static int lock(threaded_t *t)
|
||||
{
|
||||
return pthread_mutex_lock( &(t->mutex ));
|
||||
}
|
||||
static int trylock(threaded_t *t)
|
||||
{
|
||||
return pthread_mutex_trylock( &(t->mutex ));
|
||||
}
|
||||
|
||||
static int unlock(threaded_t *t)
|
||||
{
|
||||
@@ -67,6 +71,9 @@ static int eval_state(threaded_t *t, vj_tag *tag)
|
||||
lock(t);
|
||||
|
||||
if(t->state == STATE_ERROR || t->decoder == NULL) {
|
||||
|
||||
//FIXME: this part can take some time, but we must let other functions not block due to having the sema up here
|
||||
//
|
||||
if(t->decoder) {
|
||||
avhelper_close_decoder(t->decoder);
|
||||
t->decoder = NULL;
|
||||
@@ -140,6 +147,7 @@ static void *reader_thread(void *data)
|
||||
if( error ) {
|
||||
lock(t);
|
||||
t->state = STATE_ERROR;
|
||||
t->have_frame = 0;
|
||||
unlock(t);
|
||||
}
|
||||
}
|
||||
@@ -168,9 +176,12 @@ NETTHREADEXIT:
|
||||
void avformat_thread_set_state(vj_tag *tag, int new_state)
|
||||
{
|
||||
threaded_t *t = (threaded_t*) tag->priv;
|
||||
lock(t);
|
||||
t->state = new_state;
|
||||
unlock(t);
|
||||
if(trylock(t) == 0 ) {
|
||||
t->state = new_state;
|
||||
unlock(t);
|
||||
} else {
|
||||
veejay_msg(VEEJAY_MSG_WARNING,"Failed to set state, thread is busy"); //FIXME thread that initially takes a long startup time, locks main thread from controls
|
||||
}
|
||||
}
|
||||
|
||||
void *avformat_thread_allocate(VJFrame *frame)
|
||||
@@ -183,9 +194,14 @@ int avformat_thread_get_frame( vj_tag *tag, VJFrame *dst )
|
||||
{
|
||||
threaded_t *t = (threaded_t*) tag->priv;
|
||||
|
||||
lock(t);
|
||||
lock(t); //FIXME thread that initially takes a long startup time, locks main thread from controls
|
||||
|
||||
if( !(t->state==STATE_RUNNING) || t->have_frame == 0 ) {
|
||||
unlock(t);
|
||||
return 1;
|
||||
}
|
||||
VJFrame *src = avhelper_get_decoded_video(t->decoder);
|
||||
if(t->scaler == NULL) {
|
||||
if(t->scaler == NULL) {
|
||||
sws_template sws_templ;
|
||||
memset( &sws_templ, 0, sizeof(sws_template));
|
||||
sws_templ.flags = yuv_which_scaler();
|
||||
@@ -217,7 +233,7 @@ int avformat_thread_start(vj_tag *tag, VJFrame *info)
|
||||
p_err = pthread_create( &(t->thread), NULL, &reader_thread, (void*) tag );
|
||||
|
||||
if( p_err ==0) {
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Created thread for stream [%s]",tag->source_name );
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Created new input stream %d for [%s]",tag->id, tag->source_name );
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -40,8 +40,8 @@ typedef struct
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_t thread;
|
||||
int state;
|
||||
int have_frame;
|
||||
int state;
|
||||
vj_client *v;
|
||||
VJFrame *info;
|
||||
VJFrame *dest; // there is no full range YUV + alpha in PIX_FMT family
|
||||
@@ -50,6 +50,8 @@ typedef struct
|
||||
|
||||
#define STATE_INACTIVE 0
|
||||
#define STATE_RUNNING 1
|
||||
#define STATE_QUIT 2
|
||||
#define STATE_ERROR 4
|
||||
|
||||
static int lock(threaded_t *t)
|
||||
{
|
||||
@@ -61,6 +63,69 @@ static int unlock(threaded_t *t)
|
||||
return pthread_mutex_unlock( &(t->mutex ));
|
||||
}
|
||||
|
||||
static int eval_state(threaded_t *t, vj_tag *tag)
|
||||
{
|
||||
int ret = 0;
|
||||
lock(t);
|
||||
|
||||
if(t->state == STATE_ERROR || t->v == NULL) {
|
||||
if(t->v == NULL) {
|
||||
t->v = vj_client_alloc_stream(t->info);
|
||||
}
|
||||
veejay_msg(VEEJAY_MSG_INFO, " ... Waiting for network stream to become ready [%s]",tag->source_name);
|
||||
int success = vj_client_connect_dat( t->v, tag->source_name,tag->video_channel );
|
||||
if(success <= 0) {
|
||||
t->state = STATE_ERROR;
|
||||
if(t->v) {
|
||||
vj_client_close(t->v);
|
||||
vj_client_free(t->v);
|
||||
t->v = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Connecton established with %s:%d",tag->source_name, tag->video_channel + 5);
|
||||
t->state = STATE_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
ret = t->state;
|
||||
|
||||
unlock(t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eval_state_mcast(threaded_t *t, vj_tag *tag) //FIXME: split this up in seperate source files, use modular structure
|
||||
{
|
||||
int ret = 0;
|
||||
lock(t);
|
||||
|
||||
if(t->state == STATE_ERROR || t->v == NULL) {
|
||||
if(t->v == NULL) {
|
||||
t->v = vj_client_alloc_stream(t->info);
|
||||
}
|
||||
veejay_msg(VEEJAY_MSG_INFO, " ... Waiting for mcast stream to become ready [%s]",tag->source_name);
|
||||
int success = vj_client_connect( t->v, NULL, tag->source_name, tag->video_channel );
|
||||
if(success <= 0) {
|
||||
t->state = STATE_ERROR;
|
||||
if(t->v) {
|
||||
vj_client_close(t->v);
|
||||
vj_client_free(t->v);
|
||||
t->v = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Connecton established with %s:%d",tag->source_name, tag->video_channel + 5);
|
||||
t->state = STATE_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
ret = t->state;
|
||||
|
||||
unlock(t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define MS_TO_NANO(a) (a *= 1000000)
|
||||
static void net_delay(long ms, long sec )
|
||||
{
|
||||
@@ -85,114 +150,88 @@ static void *reader_thread(void *data)
|
||||
int retrieve = 0;
|
||||
int success = 0;
|
||||
|
||||
t->v = vj_client_alloc_stream(t->info);
|
||||
if(t->v == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(buf,sizeof(buf), "%03d:%d;", VIMS_GET_FRAME, my_screen_id);
|
||||
success = vj_client_connect_dat( t->v, tag->source_name,tag->video_channel );
|
||||
|
||||
if( success > 0 ) {
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Connecton established with %s:%d",tag->source_name, tag->video_channel + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
veejay_msg(0, "Unable to connect to %s: %d", tag->source_name, tag->video_channel+5);
|
||||
goto NETTHREADEXIT;
|
||||
}
|
||||
|
||||
lock(t);
|
||||
t->state = STATE_RUNNING;
|
||||
unlock(t);
|
||||
t->state = STATE_ERROR;
|
||||
|
||||
for( ;; ) {
|
||||
int error = 0;
|
||||
int res = 0;
|
||||
int ret = 0;
|
||||
|
||||
if( retrieve == 0 && t->have_frame == 0 ) {
|
||||
ret = vj_client_send( t->v, V_CMD,(unsigned char*) buf );
|
||||
if( ret <= 0 ) {
|
||||
error = 1;
|
||||
}
|
||||
else {
|
||||
retrieve = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!error && retrieve == 1 ) {
|
||||
res = vj_client_poll(t->v, V_CMD );
|
||||
if( res ) {
|
||||
if(vj_client_link_can_read( t->v, V_CMD ) ) {
|
||||
retrieve = 2;
|
||||
}
|
||||
}
|
||||
else if ( res < 0 ) {
|
||||
error = 1;
|
||||
} else if ( res == 0 ) {
|
||||
int state_eval = eval_state(t, tag);
|
||||
|
||||
switch(state_eval) {
|
||||
case STATE_INACTIVE:
|
||||
net_delay(10,0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(!error && retrieve == 2) {
|
||||
int frame_len = vj_client_read_frame_hdr( t->v );
|
||||
if( frame_len <= 0 ) {
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if( error == 0 ) {
|
||||
lock(t);
|
||||
ret = vj_client_read_frame_data( t->v, frame_len );
|
||||
unlock(t);
|
||||
}
|
||||
|
||||
if(ret) {
|
||||
t->have_frame = 1;
|
||||
retrieve = 0;
|
||||
}
|
||||
success = 0;
|
||||
continue;
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
if( retrieve == 0 ) {
|
||||
ret = vj_client_send( t->v, V_CMD,(unsigned char*) buf );
|
||||
if( ret <= 0 ) {
|
||||
error = 1;
|
||||
}
|
||||
else {
|
||||
retrieve = 1; /* queried a frame, try to fetch it */
|
||||
}
|
||||
}
|
||||
if(!error && retrieve == 1 ) {
|
||||
res = vj_client_poll(t->v, V_CMD );
|
||||
if( res ) {
|
||||
if(vj_client_link_can_read( t->v, V_CMD ) ) {
|
||||
retrieve = 2; /* data waiting at socket */
|
||||
}
|
||||
}
|
||||
else if ( res < 0 ) {
|
||||
error = 1;
|
||||
} else if ( res == 0 ) {
|
||||
net_delay(10,0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!error && retrieve == 2) {
|
||||
int frame_len = vj_client_read_frame_hdr( t->v );
|
||||
if( frame_len <= 0 ) {
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if( ret <= 0 ) {
|
||||
veejay_msg(VEEJAY_MSG_DEBUG,"Error reading video frame from %s:%d",tag->source_name,tag->video_channel );
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
NETTHREADRETRY:
|
||||
if( error == 0 ) {
|
||||
lock(t);
|
||||
ret = vj_client_read_frame_data( t->v, frame_len );
|
||||
if(ret) {
|
||||
t->have_frame = 1;
|
||||
}
|
||||
unlock(t);
|
||||
}
|
||||
|
||||
if( error )
|
||||
{
|
||||
vj_client_close(t->v);
|
||||
if(ret) {
|
||||
retrieve = 0;
|
||||
}
|
||||
|
||||
veejay_msg(VEEJAY_MSG_INFO, " ZZzzzzz ... waiting for Link %s:%d to become ready", tag->source_name, tag->video_channel );
|
||||
net_delay( 0, 5 );
|
||||
if( ret <= 0 ) {
|
||||
veejay_msg(VEEJAY_MSG_DEBUG,"Error reading video frame from %s:%d",tag->source_name,tag->video_channel );
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
if( error ) {
|
||||
lock(t);
|
||||
t->state = STATE_ERROR;
|
||||
t->have_frame = 0;
|
||||
unlock(t);
|
||||
retrieve = 0;
|
||||
|
||||
success = vj_client_connect_dat( t->v, tag->source_name,tag->video_channel );
|
||||
|
||||
if( t->state == 0 )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Network thread with %s: %d was told to exit",tag->source_name,tag->video_channel+5);
|
||||
goto NETTHREADEXIT;
|
||||
}
|
||||
}
|
||||
|
||||
if( success <= 0 )
|
||||
{
|
||||
goto NETTHREADRETRY;
|
||||
}
|
||||
else
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Connecton re-established with %s:%d",tag->source_name,tag->video_channel + 5);
|
||||
}
|
||||
|
||||
retrieve = 0;
|
||||
break;
|
||||
case STATE_QUIT:
|
||||
{
|
||||
goto NETTHREADEXIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( t->state == 0 )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Network thread with %s: %d was told to exit",tag->source_name,tag->video_channel+5);
|
||||
goto NETTHREADEXIT;
|
||||
}
|
||||
}
|
||||
|
||||
NETTHREADEXIT:
|
||||
@@ -205,6 +244,8 @@ NETTHREADEXIT:
|
||||
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Network thread with %s: %d has exited",tag->source_name,tag->video_channel+5);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -214,72 +255,35 @@ static void *mcast_reader_thread(void *data)
|
||||
vj_tag *tag = (vj_tag*) data;
|
||||
threaded_t *t = tag->priv;
|
||||
int success = 0;
|
||||
|
||||
t->v = vj_client_alloc_stream(t->info);
|
||||
if(t->v == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
success = vj_client_connect( t->v, NULL, tag->source_name, tag->video_channel );
|
||||
|
||||
if( success > 0 ) {
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Multicast connecton established with %s:%d",tag->source_name, tag->video_channel + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
veejay_msg(0, "Unable to connect to %s: %d", tag->source_name, tag->video_channel+5);
|
||||
goto NETTHREADEXIT;
|
||||
}
|
||||
|
||||
lock(t);
|
||||
t->state = STATE_RUNNING;
|
||||
unlock(t);
|
||||
|
||||
const int padded = 256;
|
||||
int max_len = padded + RUP8( 1920 * 1080 * 3 );
|
||||
|
||||
for( ;; ) {
|
||||
int error = 0;
|
||||
|
||||
if( vj_client_read_mcast_data( t->v, max_len ) < 0 ) {
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if(error == 0) {
|
||||
t->have_frame = 1;
|
||||
}
|
||||
|
||||
int state_eval = eval_state_mcast(t, tag);
|
||||
|
||||
NETTHREADRETRY:
|
||||
switch(state_eval) {
|
||||
case STATE_INACTIVE:
|
||||
net_delay(10,0);
|
||||
continue;
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
lock(t);
|
||||
if( vj_client_read_mcast_data( t->v, max_len ) < 0 ) {
|
||||
error = 1;
|
||||
}
|
||||
t->have_frame = 1;
|
||||
if( error ) {
|
||||
t->state = STATE_ERROR;
|
||||
t->have_frame = 0;
|
||||
}
|
||||
unlock(t);
|
||||
|
||||
if( error )
|
||||
{
|
||||
vj_client_close(t->v);
|
||||
|
||||
veejay_msg(VEEJAY_MSG_INFO, " ZZzzzzz ... waiting for multicast server %s:%d to become ready", tag->source_name, tag->video_channel );
|
||||
net_delay( 0, 5 );
|
||||
|
||||
success = vj_client_connect( t->v,NULL,tag->source_name,tag->video_channel );
|
||||
|
||||
if( t->state == 0 )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Multicast receiver %s: %d was told to stop",tag->source_name,tag->video_channel+5);
|
||||
break;
|
||||
case STATE_QUIT:
|
||||
goto NETTHREADEXIT;
|
||||
}
|
||||
|
||||
if( success <= 0 )
|
||||
{
|
||||
goto NETTHREADRETRY;
|
||||
}
|
||||
else
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Multicast receiver has re-established with %s:%d",tag->source_name,tag->video_channel + 5);
|
||||
}
|
||||
}
|
||||
|
||||
if( t->state == 0 )
|
||||
{
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Multicast receiver %s: %d was told to stop",tag->source_name,tag->video_channel+5);
|
||||
goto NETTHREADEXIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,16 +310,12 @@ int net_thread_get_frame( vj_tag *tag, VJFrame *dst )
|
||||
{
|
||||
threaded_t *t = (threaded_t*) tag->priv;
|
||||
|
||||
int state = 0;
|
||||
|
||||
/* frame ready ? */
|
||||
lock(t);
|
||||
state = t->state;
|
||||
if( state == 0 || t->have_frame == 0 ) {
|
||||
if(!(t->state == STATE_RUNNING) || t->have_frame == 0) {
|
||||
unlock(t);
|
||||
return 1; // not active or no frame
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
VJFrame *src = avhelper_get_decoded_video(t->v->decoder);
|
||||
|
||||
if(t->scaler == NULL) {
|
||||
@@ -326,9 +326,6 @@ int net_thread_get_frame( vj_tag *tag, VJFrame *dst )
|
||||
}
|
||||
|
||||
yuv_convert_and_scale( t->scaler, src,dst );
|
||||
|
||||
t->have_frame = 0; // frame is consumed
|
||||
|
||||
unlock(t);
|
||||
|
||||
return 1;
|
||||
@@ -346,7 +343,6 @@ int net_thread_start(vj_tag *tag, VJFrame *info)
|
||||
|
||||
pthread_mutex_init( &(t->mutex), NULL );
|
||||
|
||||
t->have_frame = 0;
|
||||
t->info = info;
|
||||
|
||||
|
||||
@@ -358,7 +354,8 @@ int net_thread_start(vj_tag *tag, VJFrame *info)
|
||||
}
|
||||
|
||||
if( p_err ==0) {
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Created new %s threaded stream to veejay host %s port %d",
|
||||
veejay_msg(VEEJAY_MSG_INFO, "Created new input stream [%d] (%s) to veejay host %s port %d",
|
||||
tag->id,
|
||||
tag->source_type == VJ_TAG_TYPE_MCAST ?
|
||||
"multicast" : "unicast", tag->source_name,tag->video_channel);
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ int vj_client_read_frame_data( vj_client *v, int datalen)
|
||||
return n;
|
||||
}
|
||||
|
||||
return avhelper_decode_video( v->decoder, v->space, n );
|
||||
return avhelper_decode_video_buffer( v->decoder, v->space, n );
|
||||
}
|
||||
|
||||
int vj_client_read_no_wait(vj_client *v, int sock_type, uint8_t *dst, int bytes )
|
||||
|
||||
Reference in New Issue
Block a user