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 = &rect;
> +    }
> +
> +    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

Reply via email to