close Warning: Can't synchronize with repository "(default)" (GIT backend not available). Look in the Trac log for more information.

Ticket #71: 0001-es_out-play-previous-frames.patch

File 0001-es_out-play-previous-frames.patch, 17.2 KB (added by rohityadav, 3 years ago)

Workaround to implement nextFrame() in libvlc, ugly hack

  • include/vlc/libvlc_media_player.h

    From 3ee43c0365862ff493792cd14dc277a9fed6d24f Mon Sep 17 00:00:00 2001
    From: Rohit Yadav <rohityadav89@gmail.com>
    Date: Sat, 10 Mar 2012 01:12:16 +0530
    Subject: [PATCH] es_out: play previous frames
    
     The idea is to simply go back
     to one frame that was already processed by the decoder and
     sent to vout for display. A simple and ugly hack is to
     display picture at time = current time minus 1.0/fps of 1
     frame, or to set time equal to current time minus 2*time it
     takes to draw two frames and then play next frame.
    
    The most acceptable solution will be to have the decode save a range of decoded frames around given current time,
    So, when a seek occurs frames after and before that point are stored in a link-list and depending upon what kind of
    behaviour is needed, in this case next frame or previous frame, that particular node can simply be used to extract
    already decoded frame it has. Note: for playing frame-by-frame, prev or next, we don't need audio frames, just video frames.
    
    The current patch is just an attempt that may be used by VLMC and libvlc based apps to play frame by frame both forward
    and backward in time.
    
    Signed-off-by: Rohit Yadav <rohityadav89@gmail.com>
    ---
     include/vlc/libvlc_media_player.h   |    6 +++++
     include/vlc_keys.h                  |    1 +
     lib/media_player.c                  |   10 +++++++++
     modules/control/hotkeys.c           |    6 +++++
     modules/gui/qt4/actions_manager.cpp |    2 +-
     src/config/keys.c                   |    1 +
     src/input/decoder.c                 |   24 ++++++++++++++++++++++
     src/input/decoder.h                 |    6 +++++
     src/input/es_out.c                  |   37 +++++++++++++++++++++++++++++++++++
     src/input/es_out.h                  |    7 ++++++
     src/input/es_out_timeshift.c        |   10 +++++++++
     src/input/input.c                   |   16 +++++++++++++++
     src/input/input_internal.h          |    1 +
     src/input/var.c                     |   18 +++++++++++++++++
     src/libvlc-module.c                 |    9 +++++++-
     src/video_output/video_output.c     |   13 ++++++++++++
     src/video_output/vout_control.h     |    5 ++++
     17 files changed, 170 insertions(+), 2 deletions(-)
    
    diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
    index cc57521..a806d75 100644
    a b LIBVLC_API int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi ); 
    793793 */
    794794LIBVLC_API int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi );
    795795
     796/**
     797 * Display the previous frame (if supported)
     798 *
     799 * \param p_mi the media player
     800 */
     801LIBVLC_API void libvlc_media_player_previous_frame( libvlc_media_player_t *p_mi );
    796802
    797803/**
    798804 * Display the next frame (if supported)
  • include/vlc_keys.h

    diff --git a/include/vlc_keys.h b/include/vlc_keys.h
    index f08243b..2e703ef 100644
    a b typedef enum vlc_action { 
    116116    ACTIONID_JUMP_FORWARD_MEDIUM,
    117117    ACTIONID_JUMP_BACKWARD_LONG,
    118118    ACTIONID_JUMP_FORWARD_LONG,
     119    ACTIONID_FRAME_PREVIOUS,
    119120    ACTIONID_FRAME_NEXT,
    120121    ACTIONID_POSITION,
    121122    ACTIONID_VOL_MUTE,
  • lib/media_player.c

    diff --git a/lib/media_player.c b/lib/media_player.c
    index b426637..1906ff8 100644
    a b int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi ) 
    13991399    return b_can_pause;
    14001400}
    14011401
     1402void libvlc_media_player_previous_frame( libvlc_media_player_t *p_mi )
     1403{
     1404    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
     1405    if( p_input_thread != NULL )
     1406    {
     1407        var_TriggerCallback( p_input_thread, "frame-previous" );
     1408        vlc_object_release( p_input_thread );
     1409    }
     1410}
     1411
    14021412void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
    14031413{
    14041414    input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
  • modules/control/hotkeys.c

    diff --git a/modules/control/hotkeys.c b/modules/control/hotkeys.c
    index d606f27..ee04e59 100644
    a b static int PutAction( intf_thread_t *p_intf, int i_action ) 
    697697            {
    698698                playlist_Stop( p_playlist );
    699699            }
     700            else if( i_action == ACTIONID_FRAME_PREVIOUS )
     701            {
     702                var_TriggerCallback( p_input, "frame-previous" );
     703                DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL,
     704                                "%s", _("Previous frame") );
     705            }
    700706            else if( i_action == ACTIONID_FRAME_NEXT )
    701707            {
    702708                var_TriggerCallback( p_input, "frame-next" );
  • modules/gui/qt4/actions_manager.cpp

    diff --git a/modules/gui/qt4/actions_manager.cpp b/modules/gui/qt4/actions_manager.cpp
    index 7cca077..abc09e4 100644
    a b void ActionsManager::frame() 
    174174{
    175175    input_thread_t *p_input = THEMIM->getInput();
    176176    if( p_input )
    177         var_TriggerCallback( p_input, "frame-next" );
     177        var_TriggerCallback( p_input, "frame-previous" );
    178178}
    179179
    180180void ActionsManager::toggleMuteAudio()
  • src/config/keys.c

    diff --git a/src/config/keys.c b/src/config/keys.c
    index b833e02..1fad66f 100644
    a b static const struct action actions[] = 
    252252    { "deinterlace", ACTIONID_DEINTERLACE, },
    253253    { "disc-menu", ACTIONID_DISC_MENU, },
    254254    { "faster", ACTIONID_FASTER, },
     255    { "frame-previous", ACTIONID_FRAME_PREVIOUS, },
    255256    { "frame-next", ACTIONID_FRAME_NEXT, },
    256257    { "incr-scalefactor", ACTIONID_SCALE_UP, },
    257258    { "intf-boss", ACTIONID_INTF_BOSS, },
  • src/input/decoder.c

    diff --git a/src/input/decoder.c b/src/input/decoder.c
    index 2e81f78..e6eb2e2 100644
    a b void input_DecoderWaitBuffering( decoder_t *p_dec ) 
    601601    vlc_mutex_unlock( &p_owner->lock );
    602602}
    603603
     604void input_DecoderFramePrevious( decoder_t *p_dec, mtime_t *pi_duration )
     605{
     606    decoder_owner_sys_t *p_owner = p_dec->p_owner;
     607
     608    *pi_duration = 0;
     609
     610    vlc_mutex_lock( &p_owner->lock );
     611    if( p_dec->fmt_out.i_cat == VIDEO_ES )
     612    {
     613        if( p_owner->b_paused && p_owner->p_vout )
     614        {
     615            vout_PreviousPicture( p_owner->p_vout, pi_duration );
     616            p_owner->pause.i_ignore++;
     617            vlc_cond_signal( &p_owner->wait_request );
     618        }
     619    }
     620    else
     621    {
     622        /* TODO subtitle should not be flushed */
     623        DecoderFlush( p_dec );
     624    }
     625    vlc_mutex_unlock( &p_owner->lock );
     626}
     627
    604628void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration )
    605629{
    606630    decoder_owner_sys_t *p_owner = p_dec->p_owner;
  • src/input/decoder.h

    diff --git a/src/input/decoder.h b/src/input/decoder.h
    index 1c9e1b6..9c90adf 100644
    a b int input_DecoderGetCcState( decoder_t *, bool *pb_decode, int i_channel ); 
    8484void input_DecoderIsCcPresent( decoder_t *, bool pb_present[4] );
    8585
    8686/**
     87 * This function force the display of the previous picture and fills the stream
     88 * time consumed.
     89 */
     90void input_DecoderFramePrevious( decoder_t *p_dec, mtime_t *pi_duration );
     91
     92/**
    8793 * This function force the display of the next picture and fills the stream
    8894 * time consumed.
    8995 */
  • src/input/es_out.c

    diff --git a/src/input/es_out.c b/src/input/es_out.c
    index 9ae8b36..ec821f3 100644
    a b static void EsOutProgramsChangeRate( es_out_t *out ) 
    784784        input_clock_ChangeRate( p_sys->pgrm[i]->p_clock, p_sys->i_rate );
    785785}
    786786
     787static void EsOutFramePrevious( es_out_t *out )
     788{
     789    es_out_sys_t *p_sys = out->p_sys;
     790    es_out_id_t *p_es_video = NULL;
     791
     792    if( p_sys->b_buffering )
     793    {
     794        msg_Warn( p_sys->p_input, "buffering, ignoring 'frame previous'" );
     795        return;
     796    }
     797
     798    assert( p_sys->b_paused );
     799
     800    for( int i = 0; i < p_sys->i_es; i++ )
     801    {
     802        es_out_id_t *p_es = p_sys->es[i];
     803
     804        if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
     805        {
     806            p_es_video = p_es;
     807            break;
     808        }
     809    }
     810
     811    if( !p_es_video )
     812    {
     813        msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame previous'" );
     814        return;
     815    }
     816
     817    var_SetTime( p_sys->p_input, "time", var_GetTime( p_sys->p_input, "time" ) - CLOCK_FREQ*4.0f/( p_sys->p_input->p->f_fps) );
     818}
     819
    787820static void EsOutFrameNext( es_out_t *out )
    788821{
    789822    es_out_sys_t *p_sys = out->p_sys;
    static int EsOutControlLocked( es_out_t *out, int i_query, va_list args ) 
    25992632            return VLC_SUCCESS;
    26002633        }
    26012634
     2635        case ES_OUT_SET_FRAME_PREVIOUS:
     2636            EsOutFramePrevious( out );
     2637            return VLC_SUCCESS;
     2638
    26022639        case ES_OUT_SET_FRAME_NEXT:
    26032640            EsOutFrameNext( out );
    26042641            return VLC_SUCCESS;
  • src/input/es_out.h

    diff --git a/src/input/es_out.h b/src/input/es_out.h
    index 56cefed..4efe915 100644
    a b enum es_out_query_private_e 
    6969    ES_OUT_SET_TIME,                                /* arg1=mtime_t             res=can fail */
    7070
    7171    /* Set next frame */
     72    ES_OUT_SET_FRAME_PREVIOUS,                      /*                          res=can fail */
     73
     74    /* Set next frame */
    7275    ES_OUT_SET_FRAME_NEXT,                          /*                          res=can fail */
    7376
    7477    /* Set position/time/length */
    static inline int es_out_SetTime( es_out_t *p_out, mtime_t i_date ) 
    134137{
    135138    return es_out_Control( p_out, ES_OUT_SET_TIME, i_date );
    136139}
     140static inline int es_out_SetFramePrevious( es_out_t *p_out )
     141{
     142    return es_out_Control( p_out, ES_OUT_SET_FRAME_PREVIOUS );
     143}
    137144static inline int es_out_SetFrameNext( es_out_t *p_out )
    138145{
    139146    return es_out_Control( p_out, ES_OUT_SET_FRAME_NEXT );
  • src/input/es_out_timeshift.c

    diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c
    index ca4d8d0..cedb795 100644
    a b static int ControlLockedSetTime( es_out_t *p_out, mtime_t i_date ) 
    567567    msg_Err( p_sys->p_input, "EsOutTimeshift does not yet support time change" );
    568568    return VLC_EGENERIC;
    569569}
     570static int ControlLockedSetFramePrevious( es_out_t *p_out )
     571{
     572    es_out_sys_t *p_sys = p_out->p_sys;
     573
     574    return es_out_SetFramePrevious( p_sys->p_out );
     575}
    570576static int ControlLockedSetFrameNext( es_out_t *p_out )
    571577{
    572578    es_out_sys_t *p_sys = p_out->p_sys;
    static int ControlLocked( es_out_t *p_out, int i_query, va_list args ) 
    672678
    673679        return ControlLockedSetTime( p_out, i_date );
    674680    }
     681    case ES_OUT_SET_FRAME_PREVIOUS:
     682    {
     683        return ControlLockedSetFramePrevious( p_out );
     684    }
    675685    case ES_OUT_SET_FRAME_NEXT:
    676686    {
    677687        return ControlLockedSetFrameNext( p_out );
  • src/input/input.c

    diff --git a/src/input/input.c b/src/input/input.c
    index 792fd05..cc652f2 100644
    a b static bool Control( input_thread_t *p_input, 
    21362136            }
    21372137            break;
    21382138
     2139        case INPUT_CONTROL_SET_FRAME_PREVIOUS:
     2140            if( p_input->p->i_state == PAUSE_S )
     2141            {
     2142                es_out_SetFramePrevious( p_input->p->p_es_out );
     2143            }
     2144            else if( p_input->p->i_state == PLAYING_S )
     2145            {
     2146                ControlPause( p_input, i_control_date );
     2147            }
     2148            else
     2149            {
     2150                msg_Err( p_input, "invalid state for frame previous" );
     2151            }
     2152            b_force_update = true;
     2153            break;
     2154
    21392155        case INPUT_CONTROL_SET_FRAME_NEXT:
    21402156            if( p_input->p->i_state == PAUSE_S )
    21412157            {
  • src/input/input_internal.h

    diff --git a/src/input/input_internal.h b/src/input/input_internal.h
    index e65acdf..072c19f 100644
    a b enum input_control_e 
    207207
    208208    INPUT_CONTROL_SET_RECORD_STATE,
    209209
     210    INPUT_CONTROL_SET_FRAME_PREVIOUS,
    210211    INPUT_CONTROL_SET_FRAME_NEXT,
    211212};
    212213
  • src/input/var.c

    diff --git a/src/input/var.c b/src/input/var.c
    index 9613fe2..7766699 100644
    a b static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd, 
    6666static int RecordCallback( vlc_object_t *p_this, char const *psz_cmd,
    6767                           vlc_value_t oldval, vlc_value_t newval,
    6868                           void *p_data );
     69static int FramePreviousCallback( vlc_object_t *p_this, char const *psz_cmd,
     70                              vlc_value_t oldval, vlc_value_t newval,
     71                              void *p_data );
    6972static int FrameNextCallback( vlc_object_t *p_this, char const *psz_cmd,
    7073                              vlc_value_t oldval, vlc_value_t newval,
    7174                              void *p_data );
    static const vlc_input_callback_t p_input_callbacks[] = 
    102105    CALLBACK( "audio-es", ESCallback ),
    103106    CALLBACK( "spu-es", ESCallback ),
    104107    CALLBACK( "record", RecordCallback ),
     108    CALLBACK( "frame-previous", FramePreviousCallback ),
    105109    CALLBACK( "frame-next", FrameNextCallback ),
    106110
    107111    CALLBACK( NULL, NULL )
    void input_ControlVarInit ( input_thread_t *p_input ) 
    138142    /* Rate */
    139143    var_Create( p_input, "rate", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
    140144
     145    var_Create( p_input, "frame-previous", VLC_VAR_VOID );
    141146    var_Create( p_input, "frame-next", VLC_VAR_VOID );
    142147
    143148    /* Position */
    static int RecordCallback( vlc_object_t *p_this, char const *psz_cmd, 
    814819    return VLC_SUCCESS;
    815820}
    816821
     822static int FramePreviousCallback( vlc_object_t *p_this, char const *psz_cmd,
     823                              vlc_value_t oldval, vlc_value_t newval,
     824                              void *p_data )
     825{
     826    input_thread_t *p_input = (input_thread_t*)p_this;
     827    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     828    VLC_UNUSED(newval);
     829
     830    input_ControlPush( p_input, INPUT_CONTROL_SET_FRAME_PREVIOUS, NULL );
     831
     832    return VLC_SUCCESS;
     833}
     834
    817835static int FrameNextCallback( vlc_object_t *p_this, char const *psz_cmd,
    818836                              vlc_value_t oldval, vlc_value_t newval,
    819837                              void *p_data )
  • src/libvlc-module.c

    diff --git a/src/libvlc-module.c b/src/libvlc-module.c
    index dbf84f2..06c9825 100644
    a b static const char *const ppsz_albumart_descriptions[] = 
    13931393#define JFLONG_KEY_TEXT N_("Long forward jump")
    13941394#define JFLONG_KEY_LONGTEXT \
    13951395    N_("Select the hotkey to make a long forward jump.")
     1396#define FRAME_PREVIOUS_KEY_TEXT N_("Previous frame")
     1397#define FRAME_PREVIOUS_KEY_LONGTEXT \
     1398    N_("Select the hotkey to go to the previous video frame.")
    13961399#define FRAME_NEXT_KEY_TEXT N_("Next frame")
    13971400#define FRAME_NEXT_KEY_LONGTEXT \
    1398     N_("Select the hotkey to got to the next video frame.")
     1401    N_("Select the hotkey to go to the next video frame.")
    13991402
    14001403#define JIEXTRASHORT_TEXT N_("Very short jump length")
    14011404#define JIEXTRASHORT_LONGTEXT N_("Very short jump length, in seconds.")
    vlc_module_begin () 
    23092312#   define KEY_JUMP_PMEDIUM       "Command+Shift+Right"
    23102313#   define KEY_JUMP_MLONG         "Command+Shift+Alt+Left"
    23112314#   define KEY_JUMP_PLONG         "Command+Shift+Alt+Right"
     2315#   define KEY_FRAME_PREVIOUS     "Ctrl+e"
    23122316#   define KEY_FRAME_NEXT         "e"
    23132317#   define KEY_NAV_ACTIVATE       "Enter"
    23142318#   define KEY_NAV_UP             "Up"
    vlc_module_begin () 
    24232427#   define KEY_JUMP_PMEDIUM       "Ctrl+Right"
    24242428#   define KEY_JUMP_MLONG         "Ctrl+Alt+Left"
    24252429#   define KEY_JUMP_PLONG         "Ctrl+Alt+Right"
     2430#   define KEY_FRAME_PREVIOUS     "Ctrl+e"
    24262431#   define KEY_FRAME_NEXT         "e"
    24272432#   define KEY_NAV_ACTIVATE       "Enter"
    24282433#   define KEY_NAV_UP             "Up"
    vlc_module_begin () 
    25592564             JBLONG_KEY_LONGTEXT, false )
    25602565    add_key( "key-jump+long", KEY_JUMP_PLONG, JFLONG_KEY_TEXT,
    25612566             JFLONG_KEY_LONGTEXT, false )
     2567    add_key( "key-frame-previous", KEY_FRAME_PREVIOUS, FRAME_PREVIOUS_KEY_TEXT,
     2568             FRAME_PREVIOUS_KEY_LONGTEXT, false )
    25622569    add_key( "key-frame-next", KEY_FRAME_NEXT, FRAME_NEXT_KEY_TEXT,
    25632570             FRAME_NEXT_KEY_LONGTEXT, false )
    25642571    add_key( "key-nav-activate", KEY_NAV_ACTIVATE, NAV_ACTIVATE_KEY_TEXT,
  • src/video_output/video_output.c

    diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
    index a8e4e24..5ca1684 100644
    a b void vout_FixLeaks( vout_thread_t *vout ) 
    342342
    343343    vlc_mutex_unlock(&vout->p->picture_lock);
    344344}
     345
     346void vout_PreviousPicture(vout_thread_t *vout, mtime_t *duration)
     347{
     348    vout_control_cmd_t cmd;
     349    vout_control_cmd_Init(&cmd, VOUT_CONTROL_STEP);
     350    cmd.u.time_ptr = duration;
     351
     352    vout->p->step.timestamp = vout->p->displayed.timestamp;
     353
     354    vout_control_Push(&vout->p->control, &cmd);
     355    vout_control_WaitEmpty(&vout->p->control);
     356}
     357
    345358void vout_NextPicture(vout_thread_t *vout, mtime_t *duration)
    346359{
    347360    vout_control_cmd_t cmd;
  • src/video_output/vout_control.h

    diff --git a/src/video_output/vout_control.h b/src/video_output/vout_control.h
    index 12b057d..2c744e8 100644
    a b void vout_FixLeaks( vout_thread_t *p_vout ); 
    6161void vout_Reset( vout_thread_t *p_vout );
    6262
    6363/**
     64 * This function will force to display the previous picture while paused
     65 */
     66void vout_PreviousPicture( vout_thread_t *p_vout, mtime_t *pi_duration );
     67
     68/**
    6469 * This function will force to display the next picture while paused
    6570 */
    6671void vout_NextPicture( vout_thread_t *p_vout, mtime_t *pi_duration );