|
|
|
@ -232,6 +232,7 @@ typedef struct VideoState { |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
int refresh; |
|
|
|
|
int last_video_stream, last_audio_stream, last_subtitle_stream; |
|
|
|
|
} VideoState; |
|
|
|
|
|
|
|
|
|
typedef struct AllocEventProps { |
|
|
|
@ -303,12 +304,11 @@ void av_noreturn exit_program(int ret) |
|
|
|
|
exit(ret); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int packet_queue_put(PacketQueue *q, AVPacket *pkt) |
|
|
|
|
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) |
|
|
|
|
{ |
|
|
|
|
AVPacketList *pkt1; |
|
|
|
|
|
|
|
|
|
/* duplicate the packet */ |
|
|
|
|
if (pkt != &flush_pkt && av_dup_packet(pkt) < 0) |
|
|
|
|
if (q->abort_request) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
pkt1 = av_malloc(sizeof(AVPacketList)); |
|
|
|
@ -317,11 +317,7 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt) |
|
|
|
|
pkt1->pkt = *pkt; |
|
|
|
|
pkt1->next = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SDL_LockMutex(q->mutex); |
|
|
|
|
|
|
|
|
|
if (!q->last_pkt) |
|
|
|
|
|
|
|
|
|
q->first_pkt = pkt1; |
|
|
|
|
else |
|
|
|
|
q->last_pkt->next = pkt1; |
|
|
|
@ -330,9 +326,25 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt) |
|
|
|
|
q->size += pkt1->pkt.size + sizeof(*pkt1); |
|
|
|
|
/* XXX: should duplicate packet data in DV case */ |
|
|
|
|
SDL_CondSignal(q->cond); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int packet_queue_put(PacketQueue *q, AVPacket *pkt) |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
/* duplicate the packet */ |
|
|
|
|
if (pkt != &flush_pkt && av_dup_packet(pkt) < 0) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
SDL_LockMutex(q->mutex); |
|
|
|
|
ret = packet_queue_put_private(q, pkt); |
|
|
|
|
SDL_UnlockMutex(q->mutex); |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (pkt != &flush_pkt && ret < 0) |
|
|
|
|
av_free_packet(pkt); |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* packet queue handling */ |
|
|
|
@ -341,7 +353,7 @@ static void packet_queue_init(PacketQueue *q) |
|
|
|
|
memset(q, 0, sizeof(PacketQueue)); |
|
|
|
|
q->mutex = SDL_CreateMutex(); |
|
|
|
|
q->cond = SDL_CreateCond(); |
|
|
|
|
packet_queue_put(q, &flush_pkt); |
|
|
|
|
q->abort_request = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void packet_queue_flush(PacketQueue *q) |
|
|
|
@ -361,7 +373,7 @@ static void packet_queue_flush(PacketQueue *q) |
|
|
|
|
SDL_UnlockMutex(q->mutex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void packet_queue_end(PacketQueue *q) |
|
|
|
|
static void packet_queue_destroy(PacketQueue *q) |
|
|
|
|
{ |
|
|
|
|
packet_queue_flush(q); |
|
|
|
|
SDL_DestroyMutex(q->mutex); |
|
|
|
@ -379,6 +391,14 @@ static void packet_queue_abort(PacketQueue *q) |
|
|
|
|
SDL_UnlockMutex(q->mutex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void packet_queue_start(PacketQueue *q) |
|
|
|
|
{ |
|
|
|
|
SDL_LockMutex(q->mutex); |
|
|
|
|
q->abort_request = 0; |
|
|
|
|
packet_queue_put_private(q, &flush_pkt); |
|
|
|
|
SDL_UnlockMutex(q->mutex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* return < 0 if aborted, 0 if no packet and > 0 if packet. */ |
|
|
|
|
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) |
|
|
|
|
{ |
|
|
|
@ -877,6 +897,9 @@ static void stream_close(VideoState *is) |
|
|
|
|
is->abort_request = 1; |
|
|
|
|
SDL_WaitThread(is->read_tid, NULL); |
|
|
|
|
SDL_WaitThread(is->refresh_tid, NULL); |
|
|
|
|
packet_queue_destroy(&is->videoq); |
|
|
|
|
packet_queue_destroy(&is->audioq); |
|
|
|
|
packet_queue_destroy(&is->subtitleq); |
|
|
|
|
|
|
|
|
|
/* free all pictures */ |
|
|
|
|
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) { |
|
|
|
@ -1816,8 +1839,13 @@ static int video_thread(void *arg) |
|
|
|
|
int last_w = is->video_st->codec->width; |
|
|
|
|
int last_h = is->video_st->codec->height; |
|
|
|
|
|
|
|
|
|
if ((ret = configure_video_filters(graph, is, vfilters)) < 0) |
|
|
|
|
if ((ret = configure_video_filters(graph, is, vfilters)) < 0) { |
|
|
|
|
SDL_Event event; |
|
|
|
|
event.type = FF_QUIT_EVENT; |
|
|
|
|
event.user.data1 = is; |
|
|
|
|
SDL_PushEvent(&event); |
|
|
|
|
goto the_end; |
|
|
|
|
} |
|
|
|
|
filt_out = is->out_video_filter; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
@ -1893,6 +1921,7 @@ static int video_thread(void *arg) |
|
|
|
|
stream_toggle_pause(is); |
|
|
|
|
} |
|
|
|
|
the_end: |
|
|
|
|
avcodec_flush_buffers(is->video_st->codec); |
|
|
|
|
#if CONFIG_AVFILTER |
|
|
|
|
av_freep(&vfilters); |
|
|
|
|
avfilter_graph_free(&graph); |
|
|
|
@ -2240,9 +2269,9 @@ static int stream_component_open(VideoState *is, int stream_index) |
|
|
|
|
opts = filter_codec_opts(codec_opts, codec, ic, ic->streams[stream_index]); |
|
|
|
|
|
|
|
|
|
switch(avctx->codec_type){ |
|
|
|
|
case AVMEDIA_TYPE_AUDIO : if(audio_codec_name ) codec= avcodec_find_decoder_by_name( audio_codec_name); break; |
|
|
|
|
case AVMEDIA_TYPE_SUBTITLE: if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break; |
|
|
|
|
case AVMEDIA_TYPE_VIDEO : if(video_codec_name ) codec= avcodec_find_decoder_by_name( video_codec_name); break; |
|
|
|
|
case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; if(audio_codec_name ) codec= avcodec_find_decoder_by_name( audio_codec_name); break; |
|
|
|
|
case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break; |
|
|
|
|
case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; if(video_codec_name ) codec= avcodec_find_decoder_by_name( video_codec_name); break; |
|
|
|
|
} |
|
|
|
|
if (!codec) |
|
|
|
|
return -1; |
|
|
|
@ -2343,20 +2372,20 @@ static int stream_component_open(VideoState *is, int stream_index) |
|
|
|
|
is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / wanted_spec.freq; |
|
|
|
|
|
|
|
|
|
memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); |
|
|
|
|
packet_queue_init(&is->audioq); |
|
|
|
|
packet_queue_start(&is->audioq); |
|
|
|
|
SDL_PauseAudio(0); |
|
|
|
|
break; |
|
|
|
|
case AVMEDIA_TYPE_VIDEO: |
|
|
|
|
is->video_stream = stream_index; |
|
|
|
|
is->video_st = ic->streams[stream_index]; |
|
|
|
|
|
|
|
|
|
packet_queue_init(&is->videoq); |
|
|
|
|
packet_queue_start(&is->videoq); |
|
|
|
|
is->video_tid = SDL_CreateThread(video_thread, is); |
|
|
|
|
break; |
|
|
|
|
case AVMEDIA_TYPE_SUBTITLE: |
|
|
|
|
is->subtitle_stream = stream_index; |
|
|
|
|
is->subtitle_st = ic->streams[stream_index]; |
|
|
|
|
packet_queue_init(&is->subtitleq); |
|
|
|
|
packet_queue_start(&is->subtitleq); |
|
|
|
|
|
|
|
|
|
is->subtitle_tid = SDL_CreateThread(subtitle_thread, is); |
|
|
|
|
break; |
|
|
|
@ -2381,7 +2410,7 @@ static void stream_component_close(VideoState *is, int stream_index) |
|
|
|
|
|
|
|
|
|
SDL_CloseAudio(); |
|
|
|
|
|
|
|
|
|
packet_queue_end(&is->audioq); |
|
|
|
|
packet_queue_flush(&is->audioq); |
|
|
|
|
av_free_packet(&is->audio_pkt); |
|
|
|
|
if (is->swr_ctx) |
|
|
|
|
swr_free(&is->swr_ctx); |
|
|
|
@ -2407,7 +2436,7 @@ static void stream_component_close(VideoState *is, int stream_index) |
|
|
|
|
|
|
|
|
|
SDL_WaitThread(is->video_tid, NULL); |
|
|
|
|
|
|
|
|
|
packet_queue_end(&is->videoq); |
|
|
|
|
packet_queue_flush(&is->videoq); |
|
|
|
|
break; |
|
|
|
|
case AVMEDIA_TYPE_SUBTITLE: |
|
|
|
|
packet_queue_abort(&is->subtitleq); |
|
|
|
@ -2422,7 +2451,7 @@ static void stream_component_close(VideoState *is, int stream_index) |
|
|
|
|
|
|
|
|
|
SDL_WaitThread(is->subtitle_tid, NULL); |
|
|
|
|
|
|
|
|
|
packet_queue_end(&is->subtitleq); |
|
|
|
|
packet_queue_flush(&is->subtitleq); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
@ -2469,9 +2498,9 @@ static int read_thread(void *arg) |
|
|
|
|
int orig_nb_streams; |
|
|
|
|
|
|
|
|
|
memset(st_index, -1, sizeof(st_index)); |
|
|
|
|
is->video_stream = -1; |
|
|
|
|
is->audio_stream = -1; |
|
|
|
|
is->subtitle_stream = -1; |
|
|
|
|
is->last_video_stream = is->video_stream = -1; |
|
|
|
|
is->last_audio_stream = is->audio_stream = -1; |
|
|
|
|
is->last_subtitle_stream = is->subtitle_stream = -1; |
|
|
|
|
|
|
|
|
|
ic = avformat_alloc_context(); |
|
|
|
|
ic->interrupt_callback.callback = decode_interrupt_cb; |
|
|
|
@ -2625,9 +2654,9 @@ static int read_thread(void *arg) |
|
|
|
|
|
|
|
|
|
/* if the queue are full, no need to read more */ |
|
|
|
|
if ( is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE |
|
|
|
|
|| ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0) |
|
|
|
|
&& (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0) |
|
|
|
|
&& (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0))) { |
|
|
|
|
|| ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request) |
|
|
|
|
&& (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request) |
|
|
|
|
&& (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request))) { |
|
|
|
|
/* wait 10 ms */ |
|
|
|
|
SDL_Delay(10); |
|
|
|
|
continue; |
|
|
|
@ -2732,6 +2761,10 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) |
|
|
|
|
is->subpq_mutex = SDL_CreateMutex(); |
|
|
|
|
is->subpq_cond = SDL_CreateCond(); |
|
|
|
|
|
|
|
|
|
packet_queue_init(&is->videoq); |
|
|
|
|
packet_queue_init(&is->audioq); |
|
|
|
|
packet_queue_init(&is->subtitleq); |
|
|
|
|
|
|
|
|
|
is->av_sync_type = av_sync_type; |
|
|
|
|
is->read_tid = SDL_CreateThread(read_thread, is); |
|
|
|
|
if (!is->read_tid) { |
|
|
|
@ -2745,16 +2778,19 @@ static void stream_cycle_channel(VideoState *is, int codec_type) |
|
|
|
|
{ |
|
|
|
|
AVFormatContext *ic = is->ic; |
|
|
|
|
int start_index, stream_index; |
|
|
|
|
int old_index; |
|
|
|
|
AVStream *st; |
|
|
|
|
|
|
|
|
|
if (codec_type == AVMEDIA_TYPE_VIDEO) |
|
|
|
|
start_index = is->video_stream; |
|
|
|
|
else if (codec_type == AVMEDIA_TYPE_AUDIO) |
|
|
|
|
start_index = is->audio_stream; |
|
|
|
|
else |
|
|
|
|
start_index = is->subtitle_stream; |
|
|
|
|
if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0)) |
|
|
|
|
return; |
|
|
|
|
if (codec_type == AVMEDIA_TYPE_VIDEO) { |
|
|
|
|
start_index = is->last_video_stream; |
|
|
|
|
old_index = is->video_stream; |
|
|
|
|
} else if (codec_type == AVMEDIA_TYPE_AUDIO) { |
|
|
|
|
start_index = is->last_audio_stream; |
|
|
|
|
old_index = is->audio_stream; |
|
|
|
|
} else { |
|
|
|
|
start_index = is->last_subtitle_stream; |
|
|
|
|
old_index = is->subtitle_stream; |
|
|
|
|
} |
|
|
|
|
stream_index = start_index; |
|
|
|
|
for (;;) { |
|
|
|
|
if (++stream_index >= is->ic->nb_streams) |
|
|
|
@ -2762,8 +2798,11 @@ static void stream_cycle_channel(VideoState *is, int codec_type) |
|
|
|
|
if (codec_type == AVMEDIA_TYPE_SUBTITLE) |
|
|
|
|
{ |
|
|
|
|
stream_index = -1; |
|
|
|
|
is->last_subtitle_stream = -1; |
|
|
|
|
goto the_end; |
|
|
|
|
} else |
|
|
|
|
} |
|
|
|
|
if (start_index == -1) |
|
|
|
|
return; |
|
|
|
|
stream_index = 0; |
|
|
|
|
} |
|
|
|
|
if (stream_index == start_index) |
|
|
|
@ -2786,7 +2825,7 @@ static void stream_cycle_channel(VideoState *is, int codec_type) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
the_end: |
|
|
|
|
stream_component_close(is, start_index); |
|
|
|
|
stream_component_close(is, old_index); |
|
|
|
|
stream_component_open(is, stream_index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|