typedef struct Frame {
AVFrame *frame;
AVSubtitle sub;
+ AVSubtitleRect **subrects; /* rescaled subtitle rectangles in yuva */
int serial;
double pts; /* presentation timestamp for the frame */
double duration; /* estimated duration of the frame */
{
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);
if (pkt != &flush_pkt && ret < 0)
- av_free_packet(pkt);
+ av_packet_unref(pkt);
return ret;
}
}
/* 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)
SDL_LockMutex(q->mutex);
for (pkt = q->first_pkt; pkt; pkt = pkt1) {
pkt1 = pkt->next;
- av_free_packet(&pkt->pkt);
+ av_packet_unref(&pkt->pkt);
av_freep(&pkt);
}
q->last_pkt = NULL;
d->next_pts_tb = d->start_pts_tb;
}
} while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
- av_free_packet(&d->pkt);
+ av_packet_unref(&d->pkt);
d->pkt_temp = d->pkt = pkt;
d->packet_pending = 1;
}
}
static void decoder_destroy(Decoder *d) {
- av_free_packet(&d->pkt);
+ av_packet_unref(&d->pkt);
}
static void frame_queue_unref_item(Frame *vp)
{
+ int i;
+ for (i = 0; i < vp->sub.num_rects; i++) {
+ av_freep(&vp->subrects[i]->data[0]);
+ av_freep(&vp->subrects[i]);
+ }
+ av_freep(&vp->subrects);
av_frame_unref(vp->frame);
avsubtitle_free(&vp->sub);
}
{
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;
int x, y, Y, U, V, A;
uint8_t *lum, *cb, *cr;
int dstx, dsty, dstw, dsth;
- const AVPicture *src = &rect->pict;
+ const AVSubtitleRect *src = rect;
dstw = av_clip(rect->w, 0, imgw);
dsth = av_clip(rect->h, 0, imgh);
pict.linesize[2] = vp->bmp->pitches[1];
for (i = 0; i < sp->sub.num_rects; i++)
- blend_subrect(&pict, sp->sub.rects[i],
+ blend_subrect(&pict, sp->subrects[i],
vp->bmp->w, vp->bmp->h);
SDL_UnlockYUVOverlay (vp->bmp);
}
}
+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);
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)
pts = sp->sub.pts / (double)AV_TIME_BASE;
sp->pts = pts;
sp->serial = is->subdec.pkt_serial;
+ if (!(sp->subrects = av_mallocz_array(sp->sub.num_rects, sizeof(AVSubtitleRect*)))) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot allocate subrects\n");
+ exit(1);
+ }
for (i = 0; i < sp->sub.num_rects; i++)
{
int subh = is->subdec.avctx->height ? is->subdec.avctx->height : is->viddec_height;
int out_w = is->viddec_width ? in_w * is->viddec_width / subw : in_w;
int out_h = is->viddec_height ? in_h * is->viddec_height / subh : in_h;
- AVPicture newpic;
- //can not use avpicture_alloc as it is not compatible with avsubtitle_free()
- av_image_fill_linesizes(newpic.linesize, AV_PIX_FMT_YUVA420P, out_w);
- newpic.data[0] = av_malloc(newpic.linesize[0] * out_h);
- newpic.data[3] = av_malloc(newpic.linesize[3] * out_h);
- newpic.data[1] = av_malloc(newpic.linesize[1] * ((out_h+1)/2));
- newpic.data[2] = av_malloc(newpic.linesize[2] * ((out_h+1)/2));
+ if (!(sp->subrects[i] = av_mallocz(sizeof(AVSubtitleRect))) ||
+ av_image_alloc(sp->subrects[i]->data, sp->subrects[i]->linesize, out_w, out_h, AV_PIX_FMT_YUVA420P, 16) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot allocate subtitle data\n");
+ exit(1);
+ }
is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,
in_w, in_h, AV_PIX_FMT_PAL8, out_w, out_h,
AV_PIX_FMT_YUVA420P, sws_flags, NULL, NULL, NULL);
- if (!is->sub_convert_ctx || !newpic.data[0] || !newpic.data[3] ||
- !newpic.data[1] || !newpic.data[2]
- ) {
+ if (!is->sub_convert_ctx) {
av_log(NULL, AV_LOG_FATAL, "Cannot initialize the sub conversion context\n");
exit(1);
}
sws_scale(is->sub_convert_ctx,
- (void*)sp->sub.rects[i]->pict.data, sp->sub.rects[i]->pict.linesize,
- 0, in_h, newpic.data, newpic.linesize);
-
- av_free(sp->sub.rects[i]->pict.data[0]);
- av_free(sp->sub.rects[i]->pict.data[1]);
- sp->sub.rects[i]->pict = newpic;
- sp->sub.rects[i]->w = out_w;
- sp->sub.rects[i]->h = out_h;
- sp->sub.rects[i]->x = sp->sub.rects[i]->x * out_w / in_w;
- sp->sub.rects[i]->y = sp->sub.rects[i]->y * out_h / in_h;
+ (void*)sp->sub.rects[i]->data, sp->sub.rects[i]->linesize,
+ 0, in_h, sp->subrects[i]->data, sp->subrects[i]->linesize);
+
+ sp->subrects[i]->w = out_w;
+ sp->subrects[i]->h = out_h;
+ sp->subrects[i]->x = sp->sub.rects[i]->x * out_w / in_w;
+ sp->subrects[i]->y = sp->sub.rects[i]->y * out_h / in_h;
}
/* now we can update the picture count */
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;
} else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
packet_queue_put(&is->subtitleq, pkt);
} else {
- av_free_packet(pkt);
+ av_packet_unref(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;
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);
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;
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);