Ejemplo n.º 1
0
static void SubpicturePrepare(vout_display_t *vd, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;
    ARect memset_bounds;

    SubtitleRegionToBounds(subpicture, &memset_bounds);

    if( subpicture )
    {
        if( subpicture->i_order == sys->i_sub_last_order
         && memcmp( &memset_bounds, &sys->sub_last_region, sizeof(ARect) ) == 0 )
            return;

        sys->i_sub_last_order = subpicture->i_order;
        sys->sub_last_region = memset_bounds;
    }

    if (AndroidWindow_LockPicture(sys, sys->p_sub_window, sys->p_sub_pic) != 0)
        return;

    /* Clear the subtitles surface. */
    SubtitleGetDirtyBounds(vd, subpicture, &memset_bounds);
    const int x_pixels_offset = memset_bounds.left
                                * sys->p_sub_pic->p[0].i_pixel_pitch;
    const int i_line_size = (memset_bounds.right - memset_bounds.left)
                            * sys->p_sub_pic->p->i_pixel_pitch;
    for (int y = memset_bounds.top; y < memset_bounds.bottom; y++)
        memset(&sys->p_sub_pic->p[0].p_pixels[y * sys->p_sub_pic->p[0].i_pitch
                                              + x_pixels_offset], 0, i_line_size);

    if (subpicture)
        picture_BlendSubpicture(sys->p_sub_pic, sys->p_spu_blend, subpicture);
}
Ejemplo n.º 2
0
int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id,
                                    block_t *in, block_t **out )
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;
    bool b_need_duplicate = false;
    picture_t *p_pic, *p_pic2 = NULL;
    *out = NULL;

    if( in == NULL )
    {
        if( p_sys->i_threads == 0 )
        {
            block_t *p_block;
            do {
                video_timer_start( id->p_encoder );
                p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL );
                video_timer_stop( id->p_encoder );
                block_ChainAppend( out, p_block );
            } while( p_block );
        }
        else
        {
            /*
             * FIXME: we need EncoderThread() to flush buffers and signal us
             * when it's done so we can send the last frames to the chain
             */
        }
        return VLC_SUCCESS;
    }


    while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) )
    {

        if( p_stream->p_sout->i_out_pace_nocontrol && p_sys->b_hurry_up )
        {
            mtime_t current_date = mdate();
            if( current_date + 50000 > p_pic->date )
            {
                msg_Dbg( p_stream, "late picture skipped (%"PRId64")",
                         current_date + 50000 - p_pic->date );
                picture_Release( p_pic );
                continue;
            }
        }

        if( p_sys->b_master_sync )
        {
            mtime_t i_video_drift;
            mtime_t i_master_drift = p_sys->i_master_drift;
            mtime_t i_pts;

            i_pts = date_Get( &id->interpolated_pts ) + 1;
            if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT
                  || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT )
            {
                msg_Dbg( p_stream, "drift is too high, resetting master sync" );
                date_Set( &id->interpolated_pts, p_pic->date );
                i_pts = p_pic->date + 1;
            }
            i_video_drift = p_pic->date - i_pts;
            b_need_duplicate = false;

            /* Set the pts of the frame being encoded */
            p_pic->date = i_pts;

            if( i_video_drift < (i_master_drift - 50000) )
            {
#if 0
                msg_Dbg( p_stream, "dropping frame (%i)",
                         (int)(i_video_drift - i_master_drift) );
#endif
                picture_Release( p_pic );
                continue;
            }
            else if( i_video_drift > (i_master_drift + 50000) )
            {
#if 0
                msg_Dbg( p_stream, "adding frame (%i)",
                         (int)(i_video_drift - i_master_drift) );
#endif
                b_need_duplicate = true;
            }
        }

        if( unlikely( !id->p_encoder->p_module ) )
        {
            transcode_video_encoder_init( p_stream, id );

            transcode_video_filter_init( p_stream, id );

            if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS )
            {
                picture_Release( p_pic );
                transcode_video_close( p_stream, id );
                id->b_transcode = false;
                return VLC_EGENERIC;
            }
        }

        /* Run filter chain */
        if( id->p_f_chain )
            p_pic = filter_chain_VideoFilter( id->p_f_chain, p_pic );

        /*
         * Encoding
         */

        /* Check if we have a subpicture to overlay */
        if( p_sys->p_spu )
        {
            video_format_t fmt;
            if( filter_chain_GetLength( id->p_f_chain ) > 0 )
                fmt = filter_chain_GetFmtOut( id->p_f_chain )->video;
            else
                fmt = id->p_decoder->fmt_out.video;

            subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt,
                                                 p_pic->date, p_pic->date, false );

            /* Overlay subpicture */
            if( p_subpic )
            {
                if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) )
                {
                    /* We can't modify the picture, we need to duplicate it */
                    picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder );
                    if( p_tmp )
                    {
                        picture_Copy( p_tmp, p_pic );
                        picture_Release( p_pic );
                        p_pic = p_tmp;
                    }
                }
                if( !p_sys->p_spu_blend )
                    p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt );
                if( p_sys->p_spu_blend )
                    picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic );
                subpicture_Delete( p_subpic );
            }
        }

        /* Run user specified filter chain */
        if( id->p_uf_chain )
            p_pic = filter_chain_VideoFilter( id->p_uf_chain, p_pic );

        if( p_sys->i_threads == 0 )
        {
            block_t *p_block;

            video_timer_start( id->p_encoder );
            p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
            video_timer_stop( id->p_encoder );

            block_ChainAppend( out, p_block );
        }

        if( p_sys->b_master_sync )
        {
            mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1;
            if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT
                  || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT )
            {
                msg_Dbg( p_stream, "drift is too high, resetting master sync" );
                date_Set( &id->interpolated_pts, p_pic->date );
                i_pts = p_pic->date + 1;
            }
            date_Increment( &id->interpolated_pts, 1 );

            if( unlikely( b_need_duplicate ) )
            {

               if( p_sys->i_threads >= 1 )
               {
                   /* We can't modify the picture, we need to duplicate it */
                   p_pic2 = video_new_buffer_decoder( id->p_decoder );
                   if( p_pic2 != NULL )
                   {
                       picture_Copy( p_pic2, p_pic );
                       p_pic2->date = i_pts;
                   }
               }
               else
               {
                   block_t *p_block;
                   p_pic->date = i_pts;
                   video_timer_start( id->p_encoder );
                   p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic);
                   video_timer_stop( id->p_encoder );
                   block_ChainAppend( out, p_block );
               }
           }
        }

        if( p_sys->i_threads == 0 )
        {
            picture_Release( p_pic );
        }
        else
        {
            vlc_mutex_lock( &p_sys->lock_out );
            p_sys->pp_pics[p_sys->i_last_pic++] = p_pic;
            p_sys->i_last_pic %= PICTURE_RING_SIZE;
            *out = p_sys->p_buffers;
            p_sys->p_buffers = NULL;
            if( p_pic2 != NULL )
            {
                p_sys->pp_pics[p_sys->i_last_pic++] = p_pic2;
                p_sys->i_last_pic %= PICTURE_RING_SIZE;
            }
            vlc_cond_signal( &p_sys->cond );
            vlc_mutex_unlock( &p_sys->lock_out );
        }
    }

    return VLC_SUCCESS;
}
Ejemplo n.º 3
0
Archivo: video.c Proyecto: chucolin/vlc
static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, sout_stream_t *p_stream, sout_stream_id_t *id, block_t **out )
{

    picture_t *p_pic2 = NULL;
    bool b_need_duplicate=false;
    /* If input pts + input_frame_interval is lower than next_output_pts - output_frame_interval
     * Then the future input frame should fit better and we can drop this one 
     *
     * Duplication need is checked in OutputFrame */
    if( ( p_pic->date + (mtime_t)id->i_input_frame_interval ) <
        ( date_Get( &id->next_output_pts ) ) )
    {
#if 0
        msg_Dbg( p_stream, "dropping frame (%"PRId64" + %"PRId64" vs %"PRId64")",
                 p_pic->date, id->i_input_frame_interval, date_Get(&id->next_output_pts) );
#endif
        picture_Release( p_pic );
        return;
    }

    /*
     * Encoding
     */
    /* Check if we have a subpicture to overlay */
    if( p_sys->p_spu )
    {
        video_format_t fmt = id->p_encoder->fmt_in.video;
        if( fmt.i_visible_width <= 0 || fmt.i_visible_height <= 0 )
        {
            fmt.i_visible_width  = fmt.i_width;
            fmt.i_visible_height = fmt.i_height;
            fmt.i_x_offset       = 0;
            fmt.i_y_offset       = 0;
        }

        subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt,
                                             p_pic->date, p_pic->date, false );

        /* Overlay subpicture */
        if( p_subpic )
        {
            if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) )
            {
                /* We can't modify the picture, we need to duplicate it,
                 * in this point the picture is already p_encoder->fmt.in format*/
                picture_t *p_tmp = video_new_buffer_encoder( id->p_encoder );
                if( likely( p_tmp ) )
                {
                    picture_Copy( p_tmp, p_pic );
                    picture_Release( p_pic );
                    p_pic = p_tmp;
                }
            }
            if( unlikely( !p_sys->p_spu_blend ) )
                p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt );
            if( likely( p_sys->p_spu_blend ) )
                picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic );
            subpicture_Delete( p_subpic );
        }
    }
    /*This pts is handled, increase clock to next one*/
    date_Increment( &id->next_output_pts, id->p_encoder->fmt_in.video.i_frame_rate_base );

    if( p_sys->i_threads == 0 )
    {
        block_t *p_block;

        p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
        block_ChainAppend( out, p_block );
    }

    /* we need to duplicate while next_output_pts + output_frame_interval < input_pts (next input pts)*/
    b_need_duplicate = ( date_Get( &id->next_output_pts ) + id->i_output_frame_interval ) <
                       ( date_Get( &id->interpolated_pts ) );

    if( p_sys->i_threads )
    {
        if( p_sys->b_master_sync )
        {
            p_pic2 = video_new_buffer_encoder( id->p_encoder );
            if( likely( p_pic2 != NULL ) )
                picture_Copy( p_pic2, p_pic );
        }
        vlc_mutex_lock( &p_sys->lock_out );
        picture_fifo_Push( p_sys->pp_pics, p_pic );
        vlc_cond_signal( &p_sys->cond );
        vlc_mutex_unlock( &p_sys->lock_out );
    }

    while( (p_sys->b_master_sync && b_need_duplicate ))
    {
        if( p_sys->i_threads >= 1 )
        {
            picture_t *p_tmp = NULL;
            /* We can't modify the picture, we need to duplicate it */
            p_tmp = video_new_buffer_encoder( id->p_encoder );
            if( likely( p_tmp != NULL ) )
            {
                picture_Copy( p_tmp, p_pic2 );
                p_tmp->date = date_Get( &id->next_output_pts );
                vlc_mutex_lock( &p_sys->lock_out );
                picture_fifo_Push( p_sys->pp_pics, p_tmp );
                vlc_cond_signal( &p_sys->cond );
                vlc_mutex_unlock( &p_sys->lock_out );
            }
        }
        else
        {
            block_t *p_block;
            p_pic->date = date_Get( &id->next_output_pts );
            p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic);
            block_ChainAppend( out, p_block );
        }
#if 0
        msg_Dbg( p_stream, "duplicated frame");
#endif
        date_Increment( &id->next_output_pts, id->p_encoder->fmt_in.video.i_frame_rate_base );
        b_need_duplicate = ( date_Get( &id->next_output_pts ) + id->i_output_frame_interval ) <
                           ( date_Get( &id->interpolated_pts ) );
    }

    if( p_sys->i_threads && p_pic2 )
        picture_Release( p_pic2 );
    else if ( p_sys->i_threads == 0 )
        picture_Release( p_pic );
}
Ejemplo n.º 4
0
Archivo: video.c Proyecto: AsamQi/vlc
static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, bool b_need_duplicate, sout_stream_t *p_stream, sout_stream_id_t *id, block_t **out )
{
    picture_t *p_pic2 = NULL;

    /*
     * Encoding
     */

    /* Check if we have a subpicture to overlay */
    if( p_sys->p_spu )
    {
        video_format_t fmt = id->p_encoder->fmt_in.video;
        if( fmt.i_visible_width <= 0 || fmt.i_visible_height <= 0 )
        {
            fmt.i_visible_width  = fmt.i_width;
            fmt.i_visible_height = fmt.i_height;
            fmt.i_x_offset       = 0;
            fmt.i_y_offset       = 0;
        }

        subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt,
                                             p_pic->date, p_pic->date, false );

        /* Overlay subpicture */
        if( p_subpic )
        {
            if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) )
            {
                /* We can't modify the picture, we need to duplicate it,
                 * in this point the picture is already p_encoder->fmt.in format*/
                picture_t *p_tmp = video_new_buffer_encoder( id->p_encoder );
                if( likely( p_tmp ) )
                {
                    picture_Copy( p_tmp, p_pic );
                    picture_Release( p_pic );
                    p_pic = p_tmp;
                }
            }
            if( unlikely( !p_sys->p_spu_blend ) )
                p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt );
            if( likely( p_sys->p_spu_blend ) )
                picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic );
            subpicture_Delete( p_subpic );
        }
    }

    if( p_sys->i_threads == 0 )
    {
        block_t *p_block;

        p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
        block_ChainAppend( out, p_block );
    }

    if( p_sys->b_master_sync )
    {
        mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1;
        mtime_t i_video_drift = p_pic->date - i_pts;
        if (unlikely ( i_video_drift  > MASTER_SYNC_MAX_DRIFT
              || i_video_drift < -MASTER_SYNC_MAX_DRIFT ) )
        {
            msg_Dbg( p_stream,
                "drift is too high (%"PRId64"), resetting master sync",
                i_video_drift );
            date_Set( &id->interpolated_pts, p_pic->date );
            i_pts = p_pic->date + 1;
        }
        date_Increment( &id->interpolated_pts, 1 );

        if( unlikely( b_need_duplicate ) )
        {

           if( p_sys->i_threads >= 1 )
           {
               /* We can't modify the picture, we need to duplicate it */
               p_pic2 = video_new_buffer_encoder( id->p_encoder );
               if( likely( p_pic2 != NULL ) )
               {
                   picture_Copy( p_pic2, p_pic );
                   p_pic2->date = i_pts;
               }
           }
           else
           {
               block_t *p_block;
               p_pic->date = i_pts;
               p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic);
               block_ChainAppend( out, p_block );
           }
       }
    }

    if( p_sys->i_threads == 0 )
    {
        picture_Release( p_pic );
    }
    else
    {
        vlc_mutex_lock( &p_sys->lock_out );
        picture_fifo_Push( p_sys->pp_pics, p_pic );
        if( p_pic2 != NULL )
        {
            picture_fifo_Push( p_sys->pp_pics, p_pic2 );
        }
        vlc_cond_signal( &p_sys->cond );
        vlc_mutex_unlock( &p_sys->lock_out );
    }
}
Ejemplo n.º 5
0
static void DisplaySubpicture(vout_display_t *vd, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;

    struct md5_s hash;
    InitMD5(&hash);
    if (subpicture) {
        for (subpicture_region_t *r = subpicture->p_region; r != NULL; r = r->p_next) {
            AddMD5(&hash, &r->i_x, sizeof(r->i_x));
            AddMD5(&hash, &r->i_y, sizeof(r->i_y));
            AddMD5(&hash, &r->fmt.i_visible_width, sizeof(r->fmt.i_visible_width));
            AddMD5(&hash, &r->fmt.i_visible_height, sizeof(r->fmt.i_visible_height));
            AddMD5(&hash, &r->fmt.i_x_offset, sizeof(r->fmt.i_x_offset));
            AddMD5(&hash, &r->fmt.i_y_offset, sizeof(r->fmt.i_y_offset));
            const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
                                      r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;

            for (int y = 0; y < r->fmt.i_visible_height; y++)
                AddMD5(&hash, &r->p_picture->p->p_pixels[pixels_offset + y*r->p_picture->p->i_pitch], r->fmt.i_visible_width);
        }
    }
    EndMD5(&hash);
    if (!memcmp(hash.buf, sys->hash, 16))
        return;
    memcpy(sys->hash, hash.buf, 16);

    jobject jsurf = jni_LockAndGetSubtitlesSurface();
    if (sys->window && jsurf != sys->jsurf)
    {
        sys->native_window.winRelease(sys->window);
        sys->window = NULL;
    }
    sys->jsurf = jsurf;
    if (!sys->window)
    {
        JNIEnv *p_env;
        jni_attach_thread(&p_env, THREAD_NAME);
        sys->window = sys->native_window.winFromSurface(p_env, jsurf);
        jni_detach_thread();
    }

    ANativeWindow_Buffer buf = { 0 };
    int32_t err = sys->native_window.winLock(sys->window, &buf, NULL);
    if (err) {
        jni_UnlockAndroidSurface();
        return;
    }

    if (buf.width >= sys->fmt.i_width && buf.height >= sys->fmt.i_height)
    {
        /* Wrap the NativeWindow corresponding to the subtitles surface in a picture_t */
        picture_t *picture = sys->subtitles_picture;
        picture->p[0].p_pixels = (uint8_t*)buf.bits;
        picture->p[0].i_lines = buf.height;
        picture->p[0].i_pitch = picture->p[0].i_pixel_pitch * buf.stride;
        /* Clear the subtitles surface. */
        memset(picture->p[0].p_pixels, 0, picture->p[0].i_pitch * picture->p[0].i_lines);
        if (subpicture)
        {
            /* Allocate a blending filter if needed. */
            if (unlikely(!sys->p_spu_blend))
                sys->p_spu_blend = filter_NewBlend(VLC_OBJECT(vd), &picture->format);
            picture_BlendSubpicture(picture, sys->p_spu_blend, subpicture);
        }
    }

    sys->native_window.unlockAndPost(sys->window);
    jni_UnlockAndroidSurface();
}