Outdated patch. See [PATCH 3/4] under '[PATCH 0/4] Support for HDMV Interactive Graphics Stream' stream.
Sorry, David Le vendredi 01 juin 2012 à 17:11 +0200, David Girault a écrit : > These changes allow testing Bluray IGS menu with avplay: > - add support for display overlay pictures, > - add support for openning a second input file as subpath, > - add some basic navigation commands to simulate and view > result of pages and buttons > > One thing don't work well now, backup/restore of YUV buffer > to allow display of main menu using still image (one GOP > video or png source) that reach eof fast. > > This may be a SDL problem, another player using GL texture > may work well. > > Signed-off-by: David Girault <[email protected]> > --- > avplay.c | 600 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 549 insertions(+), 51 deletions(-) > > diff --git a/avplay.c b/avplay.c > index d291ba3..e64e4a7 100644 > --- a/avplay.c > +++ b/avplay.c > @@ -117,6 +117,11 @@ typedef struct SubPicture { > AVSubtitle sub; > } SubPicture; > > +typedef struct OverlayPicture { > + double pts; /* presentation time stamp for this picture */ > + AVOverlay overlay; > +} OverlayPicture; > + > enum { > AV_SYNC_AUDIO_MASTER, /* default choice */ > AV_SYNC_VIDEO_MASTER, > @@ -187,6 +192,23 @@ typedef struct VideoState { > SDL_mutex *subpq_mutex; > SDL_cond *subpq_cond; > > + char overlay_subpath[1024]; > + int overlay_use_subpath; > + AVFormatContext *overlay_ic; > + > + SDL_Thread *overlay_tid; > + int overlay_stream; > + int overlay_stream_changed; > + AVStream *overlay_st; > + SDL_Overlay *overlay_bmp; ///< Used to display an > overlay picture when no new video picture is available > + double overlay_last_pts; > + PacketQueue overlayq; > + OverlayPicture ovepq[SUBPICTURE_QUEUE_SIZE]; > + int ovepq_size, ovepq_rindex, ovepq_windex; > + SDL_mutex *ovepq_mutex; > + SDL_cond *ovepq_cond; > + > + double aspect_ratio; ///< calculated when video > picture is displayed > double frame_timer; > double frame_last_pts; > double frame_last_delay; > @@ -207,6 +229,7 @@ typedef struct VideoState { > > // QETimer *video_timer; > char filename[1024]; > + > int width, height, xleft, ytop; > > PtsCorrectionContext pts_ctx; > @@ -221,10 +244,12 @@ typedef struct VideoState { > } VideoState; > > static void show_help(void); > +static void stream_handle_event(VideoState *is, SDL_Event *event); > > /* options specified by the user */ > static AVInputFormat *file_iformat; > static const char *input_filename; > +static const char *subpath_filename; > static const char *window_title; > static int fs_screen_width; > static int fs_screen_height; > @@ -236,6 +261,7 @@ static int wanted_stream[AVMEDIA_TYPE_NB] = { > [AVMEDIA_TYPE_AUDIO] = -1, > [AVMEDIA_TYPE_VIDEO] = -1, > [AVMEDIA_TYPE_SUBTITLE] = -1, > + [AVMEDIA_TYPE_OVERLAY] = -1, > }; > static int seek_by_bytes = -1; > static int display_disable; > @@ -438,7 +464,9 @@ static inline void fill_rectangle(SDL_Surface *screen, > > #define BPP 1 > > -static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int > imgw, int imgh) > +static void blend_rect(AVPicture *dst, int imgw, int imgh, > + int rw, int rh, int rx, int ry, > + Uint8 *pixels, Uint8 *palette, int linesize) > { > int wrap, wrap3, width2, skip2; > int y, u, v, a, u1, v1, a1, w, h; > @@ -447,10 +475,10 @@ static void blend_subrect(AVPicture *dst, const > AVSubtitleRect *rect, int imgw, > const uint32_t *pal; > int dstx, dsty, dstw, dsth; > > - dstw = av_clip(rect->w, 0, imgw); > - dsth = av_clip(rect->h, 0, imgh); > - dstx = av_clip(rect->x, 0, imgw - dstw); > - dsty = av_clip(rect->y, 0, imgh - dsth); > + dstw = av_clip(rw, 0, imgw); > + dsth = av_clip(rh, 0, imgh); > + dstx = av_clip(rx, 0, imgw - dstw); > + dsty = av_clip(ry, 0, imgh - dsth); > lum = dst->data[0] + dsty * dst->linesize[0]; > cb = dst->data[1] + (dsty >> 1) * dst->linesize[1]; > cr = dst->data[2] + (dsty >> 1) * dst->linesize[2]; > @@ -458,9 +486,9 @@ static void blend_subrect(AVPicture *dst, const > AVSubtitleRect *rect, int imgw, > width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1); > skip2 = dstx >> 1; > wrap = dst->linesize[0]; > - wrap3 = rect->pict.linesize[0]; > - p = rect->pict.data[0]; > - pal = (const uint32_t *)rect->pict.data[1]; /* Now in YCrCb! */ > + wrap3 = linesize; > + p = pixels; > + pal = (const uint32_t *)palette; /* Now in YCrCb! */ > > if (dsty & 1) { > lum += dstx; > @@ -638,17 +666,177 @@ static void blend_subrect(AVPicture *dst, const > AVSubtitleRect *rect, int imgw, > } > } > > +static inline void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, > int imgw, int imgh) > +{ > + blend_rect(dst, imgw, imgh, > + rect->w, rect->h, rect->x, rect->y, > + rect->pict.data[0], > + rect->pict.data[1], > + rect->pict.linesize[0]); > +} > + > +static inline void blend_overlayrect(AVPicture *dst, const AVOverlayRect > *rect, int imgw, int imgh) > +{ > + blend_rect(dst, imgw, imgh, > + rect->w, rect->h, rect->x, rect->y, > + rect->pict.data[0], > + rect->pict.data[1], > + rect->pict.linesize[0]); > +} > + > static void free_subpicture(SubPicture *sp) > { > avsubtitle_free(&sp->sub); > } > > +static void free_overlaypicture(OverlayPicture *op) > +{ > + avoverlay_free(&op->overlay); > +} > + > + > +static inline void overlay_img_backup(SDL_Overlay *bmp, Uint8 **bakpixels) > +{ > + int i; > + for (i=0;i<bmp->planes;i++) { > + bakpixels[i] = av_malloc(bmp->pitches[i]); > + memcpy(bakpixels[i], bmp->pixels[i], bmp->pitches[i]); > + } > +} > +static inline void overlay_img_restore(SDL_Overlay *bmp, Uint8 **bakpixels) > +{ > + int i; > + for (i=0;i<bmp->planes;i++) { > + memcpy(bmp->pixels[i], bakpixels[i], bmp->pitches[i]); > + av_freep(&bakpixels[i]); > + } > +} > + > +static void overlay_image_display(VideoState *is, SDL_Overlay *bmp, SDL_Rect > *rectp) > +{ > + // if rectp not NULL, we are called from video_image_display, after > video picture was displayed. > + // need to backup altered surfaces but don't require to restore previous > saved surfaces. > + // if rectp is NULL, we need to restore previous saved surfaces before > drawing new overlay pic. > + OverlayPicture *sp; > + AVPicture pict; > + SDL_Rect rect; > + int i, deleted=0; > + > + if (rectp == NULL) { > + int width, height, x, y; > + // > + height = is->height; > + width = ((int)rint(height * is->aspect_ratio)) & ~1; > + if (width > is->width) { > + width = is->width; > + height = ((int)rint(width / is->aspect_ratio)) & ~1; > + } > + x = (is->width - width) / 2; > + y = (is->height - height) / 2; > + rect.x = is->xleft + x; > + rect.y = is->ytop + y; > + rect.w = width; > + rect.h = height; > + rectp = ▭ > + } > + > + if (is->overlay_st) > + { > + int num = 2; // number of overlay pictures to keep + 1 > + if (is->overlay_stream_changed) num--; // purge all on changed stream > + > + while (is->ovepq_size >= num) { > + if (is->ovepq_size == num && !bmp && num == 1) { > + /* previous displayed overlay pictures need to be removed > from display */ > + fprintf(stderr, "Remove older overlay picture by restoring > original saved one: %dx%d@%d:%d\n", rectp->w,rectp->h,rectp->x,rectp->y); > + SDL_DisplayYUVOverlay(is->overlay_bmp, rectp); > + } > + free_overlaypicture(&is->ovepq[is->ovepq_rindex]); > + /* update queue size and signal for next picture */ > + if (++is->ovepq_rindex == SUBPICTURE_QUEUE_SIZE) > + is->ovepq_rindex = 0; > + is->ovepq_size--; > + deleted++; > + } > + > + if (is->ovepq_size > 0) > + { > + sp = &is->ovepq[is->ovepq_rindex]; > + > + /*if (is->video_current_pts > (sp->pts + ((float) > sp->overlay.end_display_time / 1000))) { > + if (!bmp) { > + // restore last backup > + fprintf(stderr, "Overlay picture timed-out, !\n"); > + SDL_DisplayYUVOverlay(is->overlay_bmp, rectp); > + } > + else { > + // do nothing, caller will display unmodified picture > + } > + } > + else */ > + if (is->video_current_pts >= sp->pts + ((float) > sp->overlay.start_display_time / 1000)) > + { > + Uint8 *bakpixels[3]; // 3 pixels planes max > + if (bmp) { > + // we have a new source, backup it then use it directly > + //fprintf(stderr, "Display new overlay picture on new > video picture (%dx%d@%d:%d)\n", rectp->w,rectp->h,rectp->x,rectp->y); > + SDL_LockYUVOverlay(bmp); > + overlay_img_backup(bmp, bakpixels); // first, save > unmodified picture > + > + // apply overlay pictures > + pict.data[0] = bmp->pixels[0]; > + pict.data[1] = bmp->pixels[2]; > + pict.data[2] = bmp->pixels[1]; > + pict.linesize[0] = bmp->pitches[0]; > + pict.linesize[1] = bmp->pitches[2]; > + pict.linesize[2] = bmp->pitches[1]; > + for (i = 0; i < sp->overlay.num_rects; i++) > + blend_overlayrect(&pict, sp->overlay.rects[i], > bmp->w, bmp->h); > + SDL_UnlockYUVOverlay (bmp); > + > + // modified bmp displayed by caller, don't do it now > + > + // store backup in our overlay_bmp > + SDL_LockYUVOverlay(is->overlay_bmp); > + overlay_img_restore(is->overlay_bmp, bakpixels); > + SDL_UnlockYUVOverlay(is->overlay_bmp); > + is->overlay_last_pts = is->video_current_pts; > + } > + else if (deleted) { > + // we don't have a source, duplicate backup and use it > + fprintf(stderr, "Display new overlay picture on old > video picture (%dx%d@%d:%d)\n", rectp->w,rectp->h,rectp->x,rectp->y); > + SDL_LockYUVOverlay (is->overlay_bmp); > + overlay_img_backup(is->overlay_bmp, bakpixels); > + > + // apply overlay pictures > + pict.data[0] = is->overlay_bmp->pixels[0]; > + pict.data[1] = is->overlay_bmp->pixels[2]; > + pict.data[2] = is->overlay_bmp->pixels[1]; > + pict.linesize[0] = is->overlay_bmp->pitches[0]; > + pict.linesize[1] = is->overlay_bmp->pitches[2]; > + pict.linesize[2] = is->overlay_bmp->pitches[1]; > + for (i = 0; i < sp->overlay.num_rects; i++) > + blend_overlayrect(&pict, sp->overlay.rects[i], > is->overlay_bmp->w, is->overlay_bmp->h); > + SDL_UnlockYUVOverlay (is->overlay_bmp); > + > + // display it right now > + SDL_DisplayYUVOverlay(is->overlay_bmp, rectp); > + > + // restore backup in our overlay_bmp > + SDL_LockYUVOverlay (is->overlay_bmp); > + overlay_img_restore(is->overlay_bmp, bakpixels); > + SDL_UnlockYUVOverlay (is->overlay_bmp); > + } > + } > + } > + } > +} > + > static void video_image_display(VideoState *is) > { > VideoPicture *vp; > SubPicture *sp; > AVPicture pict; > - float aspect_ratio; > int width, height, x, y; > SDL_Rect rect; > int i; > @@ -657,22 +845,22 @@ static void video_image_display(VideoState *is) > if (vp->bmp) { > #if CONFIG_AVFILTER > if (vp->picref->video->pixel_aspect.num == 0) > - aspect_ratio = 0; > + is->aspect_ratio = 0; > else > - aspect_ratio = av_q2d(vp->picref->video->pixel_aspect); > + is->aspect_ratio = av_q2d(vp->picref->video->pixel_aspect); > #else > > /* XXX: use variable in the frame */ > if (is->video_st->sample_aspect_ratio.num) > - aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio); > + is->aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio); > else if (is->video_st->codec->sample_aspect_ratio.num) > - aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio); > + is->aspect_ratio = > av_q2d(is->video_st->codec->sample_aspect_ratio); > else > - aspect_ratio = 0; > + is->aspect_ratio = 0; > #endif > - if (aspect_ratio <= 0.0) > - aspect_ratio = 1.0; > - aspect_ratio *= (float)vp->width / (float)vp->height; > + if (is->aspect_ratio <= 0.0) > + is->aspect_ratio = 1.0; > + is->aspect_ratio *= (float)vp->width / (float)vp->height; > > if (is->subtitle_st) > { > @@ -701,13 +889,12 @@ static void video_image_display(VideoState *is) > } > } > > - > /* XXX: we suppose the screen has a 1.0 pixel ratio */ > height = is->height; > - width = ((int)rint(height * aspect_ratio)) & ~1; > + width = ((int)rint(height * is->aspect_ratio)) & ~1; > if (width > is->width) { > width = is->width; > - height = ((int)rint(width / aspect_ratio)) & ~1; > + height = ((int)rint(width / is->aspect_ratio)) & ~1; > } > x = (is->width - width) / 2; > y = (is->height - height) / 2; > @@ -716,7 +903,11 @@ static void video_image_display(VideoState *is) > rect.y = is->ytop + y; > rect.w = width; > rect.h = height; > + > + overlay_image_display(is, vp->bmp, &rect); > + > SDL_DisplayYUVOverlay(vp->bmp, &rect); > + > } > } > > @@ -1086,7 +1277,7 @@ static void video_refresh_timer(void *opaque) > if (is->video_st) { > retry: > if (is->pictq_size == 0) { > - // nothing to do, no picture to display in the que > + // nothing to do, no picture to display in the queue > } else { > double time = av_gettime() / 1000000.0; > double next_target; > @@ -1178,6 +1369,12 @@ retry: > SDL_CondSignal(is->pictq_cond); > SDL_UnlockMutex(is->pictq_mutex); > } > + > + /* overlay may work even if no more video picture to display */ > + if (is->overlay_st) { > + overlay_image_display(is, NULL, NULL); > + } > + > } else if (is->audio_st) { > /* draw the next audio frame */ > > @@ -1191,7 +1388,7 @@ retry: > if (show_status) { > static int64_t last_time; > int64_t cur_time; > - int aqsize, vqsize, sqsize; > + int aqsize, vqsize, sqsize, oqsize; > double av_diff; > > cur_time = av_gettime(); > @@ -1199,18 +1396,21 @@ retry: > aqsize = 0; > vqsize = 0; > sqsize = 0; > + oqsize = 0; > if (is->audio_st) > aqsize = is->audioq.size; > if (is->video_st) > vqsize = is->videoq.size; > if (is->subtitle_st) > sqsize = is->subtitleq.size; > + if (is->overlay_st) > + oqsize = is->overlayq.size; > av_diff = 0; > if (is->audio_st && is->video_st) > av_diff = get_audio_clock(is) - get_video_clock(is); > - printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB > f=%"PRId64"/%"PRId64" \r", > + printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB > oq=%5dB f=%"PRId64"/%"PRId64" \r", > get_master_clock(is), av_diff, FFMAX(is->skip_frames - 1, > 0), aqsize / 1024, > - vqsize / 1024, sqsize, is->pts_ctx.num_faulty_dts, > is->pts_ctx.num_faulty_pts); > + vqsize / 1024, sqsize, oqsize, > is->pts_ctx.num_faulty_dts, is->pts_ctx.num_faulty_pts); > fflush(stdout); > last_time = cur_time; > } > @@ -1244,6 +1444,12 @@ static void stream_close(VideoState *is) > SDL_DestroyCond(is->pictq_cond); > SDL_DestroyMutex(is->subpq_mutex); > SDL_DestroyCond(is->subpq_cond); > + SDL_DestroyMutex(is->ovepq_mutex); > + SDL_DestroyCond(is->ovepq_cond); > + if (is->overlay_bmp) { > + SDL_FreeYUVOverlay(is->overlay_bmp); > + is->overlay_bmp = NULL; > + } > #if !CONFIG_AVFILTER > if (is->img_convert_ctx) > sws_freeContext(is->img_convert_ctx); > @@ -1307,6 +1513,20 @@ static void alloc_picture(void *opaque) > do_exit(); > } > > + if (!is->overlay_bmp && is->overlay_stream>=0) { > + is->overlay_bmp = SDL_CreateYUVOverlay(vp->width, vp->height, > + SDL_YV12_OVERLAY, > + screen); > + if (!is->overlay_bmp || is->overlay_bmp->pitches[0] < vp->width) { > + fprintf(stderr, "Error: the video system does not support an > image\n" > + "size of %dx%d pixels. Try using -vf \"scale=w:h\"\n" > + "to reduce the image size.\n", vp->width, vp->height ); > + do_exit(); > + } > + > + } > + > + > SDL_LockMutex(is->pictq_mutex); > vp->allocated = 1; > SDL_CondSignal(is->pictq_cond); > @@ -1927,6 +2147,77 @@ static int subtitle_thread(void *arg) > return 0; > } > > +static int overlay_thread(void *arg) > +{ > + VideoState *is = arg; > + OverlayPicture *sp; > + AVPacket pkt1, *pkt = &pkt1; > + int got_overlay; > + double pts; > + int i, j; > + int r, g, b, y, u, v, a; > + > + for (;;) { > + while (is->paused && !is->overlayq.abort_request) { > + SDL_Delay(10); > + } > + if (packet_queue_get(&is->overlayq, pkt, 1) < 0) > + break; > + > + if (pkt->data == flush_pkt.data) { > + avcodec_flush_buffers(is->overlay_st->codec); > + continue; > + } > + SDL_LockMutex(is->ovepq_mutex); > + while (is->ovepq_size >= SUBPICTURE_QUEUE_SIZE && > + !is->overlayq.abort_request) { > + SDL_CondWait(is->ovepq_cond, is->ovepq_mutex); > + } > + SDL_UnlockMutex(is->ovepq_mutex); > + > + if (is->overlayq.abort_request) > + return 0; > + > + sp = &is->ovepq[is->ovepq_windex]; > + > + /* NOTE: ipts is the PTS of the _first_ picture beginning in > + this packet, if any */ > + pts = 0; > + if (pkt->pts != AV_NOPTS_VALUE) > + pts = av_q2d(is->overlay_st->time_base) * pkt->pts; > + > + avcodec_decode_overlay2(is->overlay_st->codec, &sp->overlay, > + &got_overlay, pkt); > + > + if (got_overlay && sp->overlay.format == 0) { > + sp->pts = pts; > + > + /* RGBA->YUVA palette convertion */ > + for (i = 0; i < sp->overlay.num_rects; i++) > + { > + for (j = 0; j < sp->overlay.rects[i]->nb_colors; j++) > + { > + RGBA_IN(r, g, b, a, > (uint32_t*)sp->overlay.rects[i]->pict.data[1] + j); > + y = RGB_TO_Y_CCIR(r, g, b); > + u = RGB_TO_U_CCIR(r, g, b, 0); > + v = RGB_TO_V_CCIR(r, g, b, 0); > + YUVA_OUT((uint32_t*)sp->overlay.rects[i]->pict.data[1] + > j, y, u, v, a); > + } > + } > + > + /* now we can update the picture count */ > + if (++is->ovepq_windex == SUBPICTURE_QUEUE_SIZE) > + is->ovepq_windex = 0; > + > + SDL_LockMutex(is->ovepq_mutex); > + is->ovepq_size++; > + SDL_UnlockMutex(is->ovepq_mutex); > + } > + av_free_packet(pkt); > + } > + return 0; > +} > + > /* copy samples for viewing in editor window */ > static void update_sample_display(VideoState *is, short *samples, int > samples_size) > { > @@ -2217,17 +2508,22 @@ static void sdl_audio_callback(void *opaque, Uint8 > *stream, int len) > static int stream_component_open(VideoState *is, int stream_index) > { > AVFormatContext *ic = is->ic; > + AVFormatContext *sc = is->overlay_ic; > AVCodecContext *avctx; > AVCodec *codec; > + AVStream *stream; > SDL_AudioSpec wanted_spec, spec; > AVDictionary *opts; > AVDictionaryEntry *t = NULL; > > - if (stream_index < 0 || stream_index >= ic->nb_streams) > + if (stream_index < 0 || stream_index >= (ic->nb_streams + > (sc?sc->nb_streams:0))) > return -1; > - avctx = ic->streams[stream_index]->codec; > - > - opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, > ic->streams[stream_index]); > + if (stream_index >= ic->nb_streams) > + stream = sc->streams[stream_index-ic->nb_streams]; > + else > + stream = ic->streams[stream_index]; > + avctx = stream->codec; > + opts = filter_codec_opts(codec_opts, avctx->codec_id, > (stream_index>=ic->nb_streams ? sc : ic), stream); > > codec = avcodec_find_decoder(avctx->codec_id); > avctx->debug_mv = debug_mv; > @@ -2283,11 +2579,12 @@ static int stream_component_open(VideoState *is, int > stream_index) > is->resample_channel_layout = is->sdl_channel_layout; > } > > - ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; > + stream->discard = AVDISCARD_DEFAULT; > + > switch (avctx->codec_type) { > case AVMEDIA_TYPE_AUDIO: > is->audio_stream = stream_index; > - is->audio_st = ic->streams[stream_index]; > + is->audio_st = stream; > is->audio_buf_size = 0; > is->audio_buf_index = 0; > > @@ -2304,18 +2601,22 @@ static int stream_component_open(VideoState *is, int > stream_index) > break; > case AVMEDIA_TYPE_VIDEO: > is->video_stream = stream_index; > - is->video_st = ic->streams[stream_index]; > - > + is->video_st = stream; > packet_queue_init(&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]; > + is->subtitle_st = stream; > packet_queue_init(&is->subtitleq); > - > is->subtitle_tid = SDL_CreateThread(subtitle_thread, is); > break; > + case AVMEDIA_TYPE_OVERLAY: > + is->overlay_stream = stream_index; > + is->overlay_st = stream; > + packet_queue_init(&is->overlayq); > + is->overlay_tid = SDL_CreateThread(overlay_thread, is); > + break; > default: > break; > } > @@ -2325,11 +2626,18 @@ static int stream_component_open(VideoState *is, int > stream_index) > static void stream_component_close(VideoState *is, int stream_index) > { > AVFormatContext *ic = is->ic; > + AVFormatContext *sc = is->overlay_ic; > AVCodecContext *avctx; > + AVStream *stream; > > - if (stream_index < 0 || stream_index >= ic->nb_streams) > + if (stream_index < 0 || stream_index >= (ic->nb_streams + > (sc?sc->nb_streams:0))) > return; > - avctx = ic->streams[stream_index]->codec; > + if (stream_index >= ic->nb_streams) > + stream = sc->streams[stream_index-ic->nb_streams]; > + else > + stream = ic->streams[stream_index]; > + > + avctx = stream->codec; > > switch (avctx->codec_type) { > case AVMEDIA_TYPE_AUDIO: > @@ -2380,11 +2688,26 @@ static void stream_component_close(VideoState *is, > int stream_index) > > packet_queue_end(&is->subtitleq); > break; > + case AVMEDIA_TYPE_OVERLAY: > + packet_queue_abort(&is->overlayq); > + > + /* note: we also signal this mutex to make sure we deblock the > + video thread in all cases */ > + SDL_LockMutex(is->ovepq_mutex); > + is->overlay_stream_changed = 1; > + > + SDL_CondSignal(is->ovepq_cond); > + SDL_UnlockMutex(is->ovepq_mutex); > + > + SDL_WaitThread(is->overlay_tid, NULL); > + > + packet_queue_end(&is->overlayq); > + break; > default: > break; > } > > - ic->streams[stream_index]->discard = AVDISCARD_ALL; > + stream->discard = AVDISCARD_ALL; > avcodec_close(avctx); > switch (avctx->codec_type) { > case AVMEDIA_TYPE_AUDIO: > @@ -2399,6 +2722,10 @@ static void stream_component_close(VideoState *is, int > stream_index) > is->subtitle_st = NULL; > is->subtitle_stream = -1; > break; > + case AVMEDIA_TYPE_OVERLAY: > + is->overlay_st = NULL; > + is->overlay_stream = -1; > + break; > default: > break; > } > @@ -2418,6 +2745,7 @@ static int decode_thread(void *arg) > { > VideoState *is = arg; > AVFormatContext *ic = NULL; > + AVFormatContext *sc = NULL; > int err, i, ret; > int st_index[AVMEDIA_TYPE_NB]; > AVPacket pkt1, *pkt = &pkt1; > @@ -2431,6 +2759,7 @@ static int decode_thread(void *arg) > is->video_stream = -1; > is->audio_stream = -1; > is->subtitle_stream = -1; > + is->overlay_stream = -1; > > global_video_state = is; > > @@ -2465,6 +2794,36 @@ static int decode_thread(void *arg) > av_dict_free(&opts[i]); > av_freep(&opts); > > + if (is->overlay_use_subpath) { > + sc = avformat_alloc_context(); > + sc->interrupt_callback.callback = decode_interrupt_cb; > + err = avformat_open_input(&sc, is->overlay_subpath, NULL, > &format_opts); > + if (err < 0) { > + print_error(is->overlay_subpath, err); > + ret = -1; > + goto fail; > + } > + if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) > { > + av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); > + ret = AVERROR_OPTION_NOT_FOUND; > + goto fail; > + } > + is->overlay_ic = sc; > + > + opts = setup_find_stream_info_opts(sc, codec_opts); > + orig_nb_streams = sc->nb_streams; > + > + err = avformat_find_stream_info(sc, opts); > + if (err < 0) { > + fprintf(stderr, "%s: could not find codec parameters\n", > is->filename); > + ret = -1; > + goto fail; > + } > + for (i = 0; i < orig_nb_streams; i++) > + av_dict_free(&opts[i]); > + av_freep(&opts); > + } > + > if (ic->pb) > ic->pb->eof_reached = 0; // FIXME hack, avplay maybe should not use > url_feof() to test for the end > > @@ -2488,6 +2847,10 @@ static int decode_thread(void *arg) > > for (i = 0; i < ic->nb_streams; i++) > ic->streams[i]->discard = AVDISCARD_ALL; > + if (sc) > + for (i = 0; i < sc->nb_streams; i++) > + sc->streams[i]->discard = AVDISCARD_ALL; > + > if (!video_disable) > st_index[AVMEDIA_TYPE_VIDEO] = > av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, > @@ -2498,7 +2861,7 @@ static int decode_thread(void *arg) > wanted_stream[AVMEDIA_TYPE_AUDIO], > st_index[AVMEDIA_TYPE_VIDEO], > NULL, 0); > - if (!video_disable) > + if (!video_disable) { > st_index[AVMEDIA_TYPE_SUBTITLE] = > av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE, > wanted_stream[AVMEDIA_TYPE_SUBTITLE], > @@ -2506,8 +2869,35 @@ static int decode_thread(void *arg) > st_index[AVMEDIA_TYPE_AUDIO] : > st_index[AVMEDIA_TYPE_VIDEO]), > NULL, 0); > + if (!is->overlay_use_subpath) { > + st_index[AVMEDIA_TYPE_OVERLAY] = > + av_find_best_stream(ic, AVMEDIA_TYPE_OVERLAY, > + wanted_stream[AVMEDIA_TYPE_OVERLAY], > + (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ? > + st_index[AVMEDIA_TYPE_AUDIO] : > + st_index[AVMEDIA_TYPE_VIDEO]), > + NULL, 0); > + } > + else { > + st_index[AVMEDIA_TYPE_OVERLAY] = > + av_find_best_stream(sc, AVMEDIA_TYPE_OVERLAY, > + wanted_stream[AVMEDIA_TYPE_OVERLAY], > + (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ? > + st_index[AVMEDIA_TYPE_AUDIO] : > + st_index[AVMEDIA_TYPE_VIDEO]), > + NULL, 0); > + // found one, adjust index > + if (st_index[AVMEDIA_TYPE_OVERLAY] >= 0) { > + st_index[AVMEDIA_TYPE_OVERLAY] += ic->nb_streams; > + } > + } > + } > + > if (show_status) { > av_dump_format(ic, 0, is->filename, 0); > + if (is->overlay_use_subpath) { > + av_dump_format(sc, 1, is->overlay_subpath, 0); > + } > } > > /* open the streams */ > @@ -2529,6 +2919,10 @@ static int decode_thread(void *arg) > stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]); > } > > + if (st_index[AVMEDIA_TYPE_OVERLAY] >= 0) { > + stream_component_open(is, st_index[AVMEDIA_TYPE_OVERLAY]); > + } > + > if (is->video_stream < 0 && is->audio_stream < 0) { > fprintf(stderr, "%s: could not open codecs\n", is->filename); > ret = -1; > @@ -2564,6 +2958,13 @@ static int decode_thread(void *arg) > if (ret < 0) { > fprintf(stderr, "%s: error while seeking\n", > is->ic->filename); > } else { > + if (is->overlay_ic) { > + // also seek subpath if > + ret = avformat_seek_file(is->overlay_ic, -1, seek_min, > seek_target, seek_max, is->seek_flags); > + if (ret < 0) { > + fprintf(stderr, "%s: error while seeking\n", > is->ic->filename); > + } > + } > if (is->audio_stream >= 0) { > packet_queue_flush(&is->audioq); > packet_queue_put(&is->audioq, &flush_pkt); > @@ -2572,20 +2973,26 @@ static int decode_thread(void *arg) > packet_queue_flush(&is->subtitleq); > packet_queue_put(&is->subtitleq, &flush_pkt); > } > + if (is->overlay_stream >= 0) { > + packet_queue_flush(&is->overlayq); > + packet_queue_put(&is->overlayq, &flush_pkt); > + } > if (is->video_stream >= 0) { > packet_queue_flush(&is->videoq); > packet_queue_put(&is->videoq, &flush_pkt); > } > } > + > is->seek_req = 0; > eof = 0; > } > > /* if the queue are full, no need to read more */ > - if ( is->audioq.size + is->videoq.size + is->subtitleq.size > > MAX_QUEUE_SIZE > + if ( is->audioq.size + is->videoq.size + is->subtitleq.size + > is->overlayq.size > MAX_QUEUE_SIZE > || ( (is->audioq .size > MIN_AUDIOQ_SIZE || > 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->subtitleq.nb_packets > MIN_FRAMES || > is->subtitle_stream < 0) > + && (is->overlayq.nb_packets > MIN_FRAMES || > is->overlay_stream < 0))) { > /* wait 10 ms */ > SDL_Delay(10); > continue; > @@ -2607,7 +3014,7 @@ static int decode_thread(void *arg) > packet_queue_put(&is->audioq, pkt); > } > SDL_Delay(10); > - if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) > { > + if (is->audioq.size + is->videoq.size + is->subtitleq.size + > is->overlayq.size == 0) { > if (loop != 1 && (!loop || --loop)) { > stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? > start_time : 0, 0, 0); > } else if (autoexit) { > @@ -2638,9 +3045,33 @@ static int decode_thread(void *arg) > packet_queue_put(&is->videoq, pkt); > } else if (pkt->stream_index == is->subtitle_stream && > pkt_in_play_range) { > packet_queue_put(&is->subtitleq, pkt); > + } else if (pkt->stream_index == is->overlay_stream && > pkt_in_play_range) { > + packet_queue_put(&is->overlayq, pkt); > } else { > av_free_packet(pkt); > } > + > + if (is->overlay_ic) { > + ret = av_read_frame(is->overlay_ic, pkt); > + if (ret < 0) { > + if (is->overlay_ic->pb && is->overlay_ic->pb->error) > + break; > + continue; > + } > + /* check if packet is in play range specified by user, then > queue, otherwise discard */ > + pkt_in_play_range = duration == AV_NOPTS_VALUE || > + (pkt->pts - ic->streams[pkt->stream_index]->start_time) * > + av_q2d(ic->streams[pkt->stream_index]->time_base) - > + (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / > 1000000 > + <= ((double)duration / 1000000); > + if (pkt->stream_index == (is->subtitle_stream-ic->nb_streams) && > pkt_in_play_range) { > + packet_queue_put(&is->subtitleq, pkt); > + } else if (pkt->stream_index == > (is->overlay_stream-ic->nb_streams) && pkt_in_play_range) { > + packet_queue_put(&is->overlayq, pkt); > + } else { > + av_free_packet(pkt); > + } > + } > } > /* wait until the end */ > while (!is->abort_request) { > @@ -2659,9 +3090,14 @@ static int decode_thread(void *arg) > stream_component_close(is, is->video_stream); > if (is->subtitle_stream >= 0) > stream_component_close(is, is->subtitle_stream); > + if (is->overlay_stream >= 0) > + stream_component_close(is, is->overlay_stream); > if (is->ic) { > avformat_close_input(&is->ic); > } > + if (is->overlay_ic) { > + avformat_close_input(&is->overlay_ic); > + } > > if (ret != 0) { > SDL_Event event; > @@ -2673,7 +3109,7 @@ static int decode_thread(void *arg) > return 0; > } > > -static VideoState *stream_open(const char *filename, AVInputFormat *iformat) > +static VideoState *stream_open(const char *filename, const char *subpath, > AVInputFormat *iformat) > { > VideoState *is; > > @@ -2681,6 +3117,10 @@ static VideoState *stream_open(const char *filename, > AVInputFormat *iformat) > if (!is) > return NULL; > av_strlcpy(is->filename, filename, sizeof(is->filename)); > + if (subpath) { > + av_strlcpy(is->overlay_subpath, subpath, > sizeof(is->overlay_subpath)); > + is->overlay_use_subpath = 1; > + } > is->iformat = iformat; > is->ytop = 0; > is->xleft = 0; > @@ -2692,6 +3132,9 @@ static VideoState *stream_open(const char *filename, > AVInputFormat *iformat) > is->subpq_mutex = SDL_CreateMutex(); > is->subpq_cond = SDL_CreateCond(); > > + is->ovepq_mutex = SDL_CreateMutex(); > + is->ovepq_cond = SDL_CreateCond(); > + > is->av_sync_type = av_sync_type; > is->parse_tid = SDL_CreateThread(decode_thread, is); > if (!is->parse_tid) { > @@ -2701,6 +3144,34 @@ static VideoState *stream_open(const char *filename, > AVInputFormat *iformat) > return is; > } > > +static void stream_handle_event(VideoState *is, SDL_Event *event) > +{ > + AVPacket pkt1, *pkt = &pkt1; > + char key = 0; > + if (event != NULL && event->type == SDL_KEYDOWN) > switch(event->key.keysym.sym) { > + case SDLK_RETURN: key = 13; break; // activate current button > + case SDLK_u: key = 'u'; break; // up > + case SDLK_d: key = 'd'; break; // down > + case SDLK_l: key = 'l'; break; // left > + case SDLK_r: key = 'r'; break; // right > + case SDLK_p: key = 'p'; break; // roll pages > + } > + > + //pass key to decoder using a fake packet > + if (is->overlay_stream >= 0) { > + av_init_packet(pkt); > + pkt->size = (key != 0 ? 4 : 3); > + pkt->data = av_mallocz(pkt->size); > + *(pkt->data) = 0x80; > + *(pkt->data+1) = 0x00; > + *(pkt->data+2) = (key != 0 ? 1 : 0); > + if (key != 0) > + *(char*)(pkt->data+3) = key; > + pkt->stream_index = is->overlay_stream; > + packet_queue_put(&is->overlayq, pkt); > + } > +} > + > static void stream_cycle_channel(VideoState *is, int codec_type) > { > AVFormatContext *ic = is->ic; > @@ -2711,15 +3182,17 @@ static void stream_cycle_channel(VideoState *is, int > codec_type) > start_index = is->video_stream; > else if (codec_type == AVMEDIA_TYPE_AUDIO) > start_index = is->audio_stream; > - else > + else if (codec_type == AVMEDIA_TYPE_SUBTITLE) > start_index = is->subtitle_stream; > - if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0)) > + else > + start_index = is->overlay_stream; > + if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE || codec_type == > AVMEDIA_TYPE_OVERLAY ? -1 : 0)) > return; > stream_index = start_index; > for (;;) { > if (++stream_index >= is->ic->nb_streams) > { > - if (codec_type == AVMEDIA_TYPE_SUBTITLE) > + if (codec_type == AVMEDIA_TYPE_SUBTITLE || codec_type == > AVMEDIA_TYPE_OVERLAY) > { > stream_index = -1; > goto the_end; > @@ -2739,6 +3212,7 @@ static void stream_cycle_channel(VideoState *is, int > codec_type) > break; > case AVMEDIA_TYPE_VIDEO: > case AVMEDIA_TYPE_SUBTITLE: > + case AVMEDIA_TYPE_OVERLAY: > goto the_end; > default: > break; > @@ -2815,7 +3289,6 @@ static void event_loop(void) > case SDLK_f: > toggle_full_screen(); > break; > - case SDLK_p: > case SDLK_SPACE: > toggle_pause(); > break; > @@ -2834,6 +3307,20 @@ static void event_loop(void) > if (cur_stream) > stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE); > break; > + case SDLK_o: > + if (cur_stream) > + stream_cycle_channel(cur_stream, AVMEDIA_TYPE_OVERLAY); > + break; > + case SDLK_RETURN: > + case SDLK_u: > + case SDLK_d: > + case SDLK_l: > + case SDLK_r: > + case SDLK_p: > + if (cur_stream) > + stream_handle_event(cur_stream, &event); > + break; > + > case SDLK_w: > toggle_audio_display(); > break; > @@ -3084,24 +3571,35 @@ static void show_help(void) > printf("\nWhile playing:\n" > "q, ESC quit\n" > "f toggle full screen\n" > - "p, SPC pause\n" > + "SPC pause\n" > "a cycle audio channel\n" > "v cycle video channel\n" > "t cycle subtitle channel\n" > + "o cycle overlay channel\n" > "w show audio waves\n" > "s activate frame-step mode\n" > "left/right seek backward/forward 10 seconds\n" > "down/up seek backward/forward 1 minute\n" > "mouse click seek to percentage in file corresponding to > fraction of width\n" > + "u navigate 'up' in overlay\n" > + "d navigate 'down' in overlay\n" > + "l navigate 'left' in overlay\n" > + "r navigate 'right' in overlay\n" > + "ENTER activate selected overlay button\n" > + "p toggle overlay display (popup menu)\n" > ); > } > > static void opt_input_file(void *optctx, const char *filename) > { > if (input_filename) { > - fprintf(stderr, "Argument '%s' provided as input filename, but '%s' > was already specified.\n", > - filename, input_filename); > - exit(1); > + if (subpath_filename) { > + fprintf(stderr, "Argument '%s' provided as subpath filename, but > '%s' was already specified.\n", > + filename, subpath_filename); > + exit(1); > + } > + subpath_filename = filename; > + return; > } > if (!strcmp(filename, "-")) > filename = "pipe:"; > @@ -3167,7 +3665,7 @@ int main(int argc, char **argv) > av_init_packet(&flush_pkt); > flush_pkt.data = "FLUSH"; > > - cur_stream = stream_open(input_filename, file_iformat); > + cur_stream = stream_open(input_filename, subpath_filename, file_iformat); > > event_loop(); > _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
