/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
+/* Step size for volume control */
+#define SDL_VOLUME_STEP (SDL_MIX_MAXVOLUME / 50)
+
/* no AV sync correction is done if below the minimum AV sync threshold */
#define AV_SYNC_THRESHOLD_MIN 0.04
/* AV sync correction is done if above the maximum AV sync threshold */
unsigned int audio_buf1_size;
int audio_buf_index; /* in bytes */
int audio_write_buf_size;
+ int audio_volume;
+ int muted;
struct AudioParams audio_src;
#if CONFIG_AVFILTER
struct AudioParams audio_filter_src;
SDL_Rect last_display_rect;
int eof;
- char filename[1024];
+ char *filename;
int width, height, xleft, ytop;
int step;
}
/* packet queue handling */
-static void packet_queue_init(PacketQueue *q)
+static int packet_queue_init(PacketQueue *q)
{
memset(q, 0, sizeof(PacketQueue));
q->mutex = SDL_CreateMutex();
+ if (!q->mutex) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
+ return AVERROR(ENOMEM);
+ }
q->cond = SDL_CreateCond();
+ if (!q->cond) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
+ return AVERROR(ENOMEM);
+ }
q->abort_request = 1;
+ return 0;
}
static void packet_queue_flush(PacketQueue *q)
{
int i;
memset(f, 0, sizeof(FrameQueue));
- if (!(f->mutex = SDL_CreateMutex()))
+ if (!(f->mutex = SDL_CreateMutex())) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
- if (!(f->cond = SDL_CreateCond()))
+ }
+ if (!(f->cond = SDL_CreateCond())) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
+ }
f->pktq = pktq;
f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
f->keep_last = !!keep_last;
}
}
+static void stream_component_close(VideoState *is, int stream_index)
+{
+ AVFormatContext *ic = is->ic;
+ AVCodecContext *avctx;
+
+ if (stream_index < 0 || stream_index >= ic->nb_streams)
+ return;
+ avctx = ic->streams[stream_index]->codec;
+
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ decoder_abort(&is->auddec, &is->sampq);
+ SDL_CloseAudio();
+ decoder_destroy(&is->auddec);
+ swr_free(&is->swr_ctx);
+ av_freep(&is->audio_buf1);
+ is->audio_buf1_size = 0;
+ is->audio_buf = NULL;
+
+ if (is->rdft) {
+ av_rdft_end(is->rdft);
+ av_freep(&is->rdft_data);
+ is->rdft = NULL;
+ is->rdft_bits = 0;
+ }
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ decoder_abort(&is->viddec, &is->pictq);
+ decoder_destroy(&is->viddec);
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ decoder_abort(&is->subdec, &is->subpq);
+ decoder_destroy(&is->subdec);
+ break;
+ default:
+ break;
+ }
+
+ ic->streams[stream_index]->discard = AVDISCARD_ALL;
+ avcodec_close(avctx);
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ is->audio_st = NULL;
+ is->audio_stream = -1;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ is->video_st = NULL;
+ is->video_stream = -1;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ is->subtitle_st = NULL;
+ is->subtitle_stream = -1;
+ break;
+ default:
+ break;
+ }
+}
+
static void stream_close(VideoState *is)
{
/* XXX: use a special url_shutdown call to abort parse cleanly */
is->abort_request = 1;
SDL_WaitThread(is->read_tid, NULL);
+
+ /* close each stream */
+ if (is->audio_stream >= 0)
+ stream_component_close(is, is->audio_stream);
+ if (is->video_stream >= 0)
+ stream_component_close(is, is->video_stream);
+ if (is->subtitle_stream >= 0)
+ stream_component_close(is, is->subtitle_stream);
+
+ avformat_close_input(&is->ic);
+
packet_queue_destroy(&is->videoq);
packet_queue_destroy(&is->audioq);
packet_queue_destroy(&is->subtitleq);
sws_freeContext(is->img_convert_ctx);
#endif
sws_freeContext(is->sub_convert_ctx);
+ av_free(is->filename);
av_free(is);
}
is->step = 0;
}
+static void toggle_mute(VideoState *is)
+{
+ is->muted = !is->muted;
+}
+
+static void update_volume(VideoState *is, int sign, int step)
+{
+ is->audio_volume = av_clip(is->audio_volume + sign * step, 0, SDL_MIX_MAXVOLUME);
+}
+
static void step_to_next_frame(VideoState *is)
{
/* if the stream is paused unpause it, then step */
return ret;
}
-static void decoder_start(Decoder *d, int (*fn)(void *), void *arg)
+static int decoder_start(Decoder *d, int (*fn)(void *), void *arg)
{
packet_queue_start(d->queue);
d->decoder_tid = SDL_CreateThread(fn, arg);
+ if (!d->decoder_tid) {
+ av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
+ return AVERROR(ENOMEM);
+ }
+ return 0;
}
static int video_thread(void *arg)
len1 = is->audio_buf_size - is->audio_buf_index;
if (len1 > len)
len1 = len;
- memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
+ if (!is->muted && is->audio_volume == SDL_MIX_MAXVOLUME)
+ memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
+ else {
+ memset(stream, is->silence_buf[0], len1);
+ if (!is->muted)
+ SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume);
+ }
len -= len1;
stream += len1;
is->audio_buf_index += len1;
is->auddec.start_pts = is->audio_st->start_time;
is->auddec.start_pts_tb = is->audio_st->time_base;
}
- decoder_start(&is->auddec, audio_thread, is);
+ if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0)
+ goto fail;
SDL_PauseAudio(0);
break;
case AVMEDIA_TYPE_VIDEO:
is->viddec_height = avctx->height;
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
- decoder_start(&is->viddec, video_thread, is);
+ if ((ret = decoder_start(&is->viddec, video_thread, is)) < 0)
+ goto fail;
is->queue_attachments_req = 1;
break;
case AVMEDIA_TYPE_SUBTITLE:
is->subtitle_st = ic->streams[stream_index];
decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
- decoder_start(&is->subdec, subtitle_thread, is);
+ if ((ret = decoder_start(&is->subdec, subtitle_thread, is)) < 0)
+ goto fail;
break;
default:
break;
return ret;
}
-static void stream_component_close(VideoState *is, int stream_index)
-{
- AVFormatContext *ic = is->ic;
- AVCodecContext *avctx;
-
- if (stream_index < 0 || stream_index >= ic->nb_streams)
- return;
- avctx = ic->streams[stream_index]->codec;
-
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- decoder_abort(&is->auddec, &is->sampq);
- SDL_CloseAudio();
- decoder_destroy(&is->auddec);
- swr_free(&is->swr_ctx);
- av_freep(&is->audio_buf1);
- is->audio_buf1_size = 0;
- is->audio_buf = NULL;
-
- if (is->rdft) {
- av_rdft_end(is->rdft);
- av_freep(&is->rdft_data);
- is->rdft = NULL;
- is->rdft_bits = 0;
- }
- break;
- case AVMEDIA_TYPE_VIDEO:
- decoder_abort(&is->viddec, &is->pictq);
- decoder_destroy(&is->viddec);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- decoder_abort(&is->subdec, &is->subpq);
- decoder_destroy(&is->subdec);
- break;
- default:
- break;
- }
-
- ic->streams[stream_index]->discard = AVDISCARD_ALL;
- avcodec_close(avctx);
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- is->audio_st = NULL;
- is->audio_stream = -1;
- break;
- case AVMEDIA_TYPE_VIDEO:
- is->video_st = NULL;
- is->video_stream = -1;
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- is->subtitle_st = NULL;
- is->subtitle_stream = -1;
- break;
- default:
- break;
- }
-}
-
static int decode_interrupt_cb(void *ctx)
{
VideoState *is = ctx;
int scan_all_pmts_set = 0;
int64_t pkt_ts;
+ if (!wait_mutex) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
memset(st_index, -1, sizeof(st_index));
is->last_video_stream = is->video_stream = -1;
is->last_audio_stream = is->audio_stream = -1;
av_free_packet(pkt);
}
}
- /* wait until the end */
- while (!is->abort_request) {
- SDL_Delay(100);
- }
ret = 0;
fail:
- /* close each stream */
- if (is->audio_stream >= 0)
- stream_component_close(is, is->audio_stream);
- if (is->video_stream >= 0)
- stream_component_close(is, is->video_stream);
- if (is->subtitle_stream >= 0)
- stream_component_close(is, is->subtitle_stream);
- if (ic) {
+ if (ic && !is->ic)
avformat_close_input(&ic);
- is->ic = NULL;
- }
if (ret != 0) {
SDL_Event event;
is = av_mallocz(sizeof(VideoState));
if (!is)
return NULL;
- av_strlcpy(is->filename, filename, sizeof(is->filename));
+ is->filename = av_strdup(filename);
+ if (!is->filename)
+ goto fail;
is->iformat = iformat;
is->ytop = 0;
is->xleft = 0;
if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
goto fail;
- packet_queue_init(&is->videoq);
- packet_queue_init(&is->audioq);
- packet_queue_init(&is->subtitleq);
+ if (packet_queue_init(&is->videoq) < 0 ||
+ packet_queue_init(&is->audioq) < 0 ||
+ packet_queue_init(&is->subtitleq) < 0)
+ goto fail;
- is->continue_read_thread = SDL_CreateCond();
+ if (!(is->continue_read_thread = SDL_CreateCond())) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
+ goto fail;
+ }
init_clock(&is->vidclk, &is->videoq.serial);
init_clock(&is->audclk, &is->audioq.serial);
init_clock(&is->extclk, &is->extclk.serial);
is->audio_clock_serial = -1;
+ is->audio_volume = SDL_MIX_MAXVOLUME;
+ is->muted = 0;
is->av_sync_type = av_sync_type;
is->read_tid = SDL_CreateThread(read_thread, is);
if (!is->read_tid) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
fail:
stream_close(is);
return NULL;
case SDLK_SPACE:
toggle_pause(cur_stream);
break;
+ case SDLK_m:
+ toggle_mute(cur_stream);
+ break;
+ case SDLK_KP_MULTIPLY:
+ case SDLK_0:
+ update_volume(cur_stream, 1, SDL_VOLUME_STEP);
+ break;
+ case SDLK_KP_DIVIDE:
+ case SDLK_9:
+ update_volume(cur_stream, -1, SDL_VOLUME_STEP);
+ break;
case SDLK_s: // S: Step to next frame
step_to_next_frame(cur_stream);
break;
"q, ESC quit\n"
"f toggle full screen\n"
"p, SPC pause\n"
+ "m toggle mute\n"
+ "9, 0 decrease and increase volume respectively\n"
+ "/, * decrease and increase volume respectively\n"
"a cycle audio channel in the current program\n"
"v cycle video channel\n"
"t cycle subtitle channel in the current program\n"
switch(op) {
case AV_LOCK_CREATE:
*mtx = SDL_CreateMutex();
- if(!*mtx)
+ if(!*mtx) {
+ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return 1;
+ }
return 0;
case AV_LOCK_OBTAIN:
return !!SDL_LockMutex(*mtx);
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
+ SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+
if (av_lockmgr_register(lockmgr)) {
av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
do_exit(NULL);