static void hb_qsv_filter_pre_close( hb_filter_object_t * filter ){
    int i = 0;
    mfxStatus sts = MFX_ERR_NONE;

    hb_filter_private_t * pv = filter->private_data;

    if ( !pv )
    {
        return;
    }

    sws_freeContext(pv->sws_context_to_nv12);
    sws_freeContext(pv->sws_context_from_nv12);

    av_qsv_context* qsv = pv->job->qsv;
    if(qsv && qsv->vpp_space && av_qsv_list_count(qsv->vpp_space) > 0 ){
        if(pv->qsv_user && qsv->mfx_session){

            sts=MFXVideoUSER_Unregister(qsv->mfx_session,0);
            AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

            for(i=hb_list_count(pv->qsv_user);i>0;i--){
                qsv_filter_t *plugin = hb_list_item(pv->qsv_user,i-1);
                hb_list_rem(pv->qsv_user,plugin);
                plugin_close(plugin);
            }
            hb_list_close(&pv->qsv_user);
        }

        // closing local stuff
        qsv_filter_close(qsv,AV_QSV_VPP_USER);

        // closing the commong stuff
        av_qsv_context_clean(qsv);
    }
    hb_cond_close(&pv->pre.frame_completed);
    hb_lock_close(&pv->pre.frame_completed_lock);

    hb_cond_close(&pv->post.frame_completed);
    hb_lock_close(&pv->post.frame_completed_lock);

    hb_cond_close(&pv->pre_busy.frame_completed);
    hb_lock_close(&pv->pre_busy.frame_completed_lock);

    hb_cond_close(&pv->post_busy.frame_completed);
    hb_lock_close(&pv->post_busy.frame_completed_lock);

    hb_list_close( &pv->list );

    free( pv );
    filter->private_data = NULL;
}
static int hb_qsv_filter_pre_work( hb_filter_object_t * filter,
                               hb_buffer_t ** buf_in,
                               hb_buffer_t ** buf_out ){
    hb_filter_private_t * pv = filter->private_data;
    hb_buffer_t * in = *buf_in;
    hb_buffer_t * out = *buf_out;
    int sts = 0;

    av_qsv_context* qsv = pv->job->qsv;

    if(!in->qsv_details.filter_details)
        in->qsv_details.filter_details = pv;

    if ( in->size <= 0 )
    {
        *buf_out = in;
        *buf_in = NULL;
        return HB_FILTER_DONE;
    }

    while(1){
        int ret = filter_pre_init(qsv,pv);
        if(ret >= 2)
            av_qsv_sleep(1);
        else
            break;
    }

    pv->pre.in  = in;
    pv->pre.out = in;

    sts = pre_process_frame(in, qsv, pv);

    if(sts){
        hb_list_add(pv->list,out);
    }

    if( hb_list_count(pv->list) ){
        *buf_out = hb_list_item(pv->list,0);
        hb_list_rem(pv->list,*buf_out);
         *buf_in = NULL;
    }
    else{
        *buf_in = NULL;
        *buf_out = in;
    }

    return HB_FILTER_OK;
}
Exemple #3
0
/***********************************************************************
 * hb_batch_close
 ***********************************************************************
 * Closes and frees everything
 **********************************************************************/
void hb_batch_close( hb_batch_t ** _d )
{
    hb_batch_t * d = *_d;
    char       * filename;

    while ( ( filename = hb_list_item( d->list_file, 0 ) ) )
    {
        hb_list_rem( d->list_file, filename );
        free( filename );
    }
    hb_list_close( &d->list_file );
    free( d->path );
    free( d );
    *_d = NULL;
}
Exemple #4
0
static void hb_opencl_devices_list_close(hb_list_t **_list)
{
    if (_list != NULL)
    {
        hb_list_t *list = *_list;
        hb_opencl_device_t *device;
        while (list != NULL && hb_list_count(list) > 0)
        {
            if ((device = hb_list_item(list, 0)) != NULL)
            {
                hb_list_rem(list, device);
                free(device);
            }
        }
    }
    hb_list_close(_list);
}
Exemple #5
0
void encx265Close(hb_work_object_t *w)
{
    hb_work_private_t *pv = w->private_data;

    if (pv->delayed_chapters != NULL)
    {
        struct chapter_s *item;
        while ((item = hb_list_item(pv->delayed_chapters, 0)) != NULL)
        {
            hb_list_rem(pv->delayed_chapters, item);
            free(item);
        }
        hb_list_close(&pv->delayed_chapters);
    }

    x265_param_free(pv->param);
    x265_encoder_close(pv->x265);
    free(pv);
    w->private_data = NULL;
}
Exemple #6
0
/**
 * Iterates through job list and calls do_job for each job.
 * @param _work Handle work object.
 */
static void work_func( void * _work )
{
    hb_work_t  * work = _work;
    hb_job_t   * job;

    hb_log( "%d job(s) to process", hb_list_count( work->jobs ) );

    while( !*work->die && ( job = hb_list_item( work->jobs, 0 ) ) )
    {
        hb_list_rem( work->jobs, job );
        job->die = work->die;
        *(work->current_job) = job;
        InitWorkState( job->h );
        do_job( job );
        *(work->current_job) = NULL;
    }

    *(work->error) = HB_ERROR_NONE;

    free( work );
}
mfxStatus plugin_close(qsv_filter_t* plugin){
    int i = 0;
    mfxStatus sts = MFX_ERR_NONE;

    if(!plugin->is_init_done) return sts;

    mfxExtOpaqueSurfaceAlloc* plugin_opaque_alloc = NULL;

    plugin_opaque_alloc = (mfxExtOpaqueSurfaceAlloc*) get_ext_buffer(plugin->videoparam->ExtParam,
                                    plugin->videoparam->NumExtParam, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION);

    if(!plugin_opaque_alloc || !plugin_opaque_alloc->In.Surfaces || !plugin_opaque_alloc->Out.Surfaces)
        return MFX_ERR_INVALID_VIDEO_PARAM;

    sts = plugin->core->UnmapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->In.NumSurface,
            plugin_opaque_alloc->In.Type, plugin_opaque_alloc->In.Surfaces);
    AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);


    sts = plugin->core->UnmapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->Out.NumSurface,
            plugin_opaque_alloc->Out.Type, plugin_opaque_alloc->Out.Surfaces);
    AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    if(plugin->tasks){
        for(i=hb_list_count(plugin->tasks);i>0;i--){
            qsv_filter_task_t *task = hb_list_item(plugin->tasks,i-1);
            hb_list_rem(plugin->tasks,task);
            free(task);
        }
        hb_list_close(&plugin->tasks);
    }

    plugin->is_init_done = 0;

    return sts;
}
Exemple #8
0
static hb_buffer_t* nal_encode(hb_work_object_t *w,
                               x265_picture *pic_out,
                               x265_nal *nal, uint32_t nnal)
{
    hb_work_private_t *pv = w->private_data;
    hb_job_t *job         = pv->job;
    hb_buffer_t *buf      = NULL;
    int i;

    if (nnal <= 0)
    {
        return NULL;
    }

    buf = hb_video_buffer_init(job->width, job->height);
    if (buf == NULL)
    {
        return NULL;
    }

    buf->size = 0;
    // copy the bitstream data
    for (i = 0; i < nnal; i++)
    {
        memcpy(buf->data + buf->size, nal[i].payload, nal[i].sizeBytes);
        buf->size += nal[i].sizeBytes;
    }

    // use the pts to get the original frame's duration.
    buf->s.duration     = get_frame_duration(pv, pic_out->pts);
    buf->s.stop         = pic_out->pts + buf->s.duration;
    buf->s.start        = pic_out->pts;
    buf->s.renderOffset = pic_out->dts;
    if (w->config->h264.init_delay == 0 && pic_out->dts < 0)
    {
        w->config->h264.init_delay -= pic_out->dts;
    }

    switch (pic_out->sliceType)
    {
        case X265_TYPE_IDR:
            buf->s.frametype = HB_FRAME_IDR;
            break;
        case X265_TYPE_I:
            buf->s.frametype = HB_FRAME_I;
            break;
        case X265_TYPE_P:
            buf->s.frametype = HB_FRAME_P;
            break;
        case X265_TYPE_B:
            buf->s.frametype = HB_FRAME_B;
            break;
        case X265_TYPE_BREF:
            buf->s.frametype = HB_FRAME_BREF;
            break;
        default:
            buf->s.frametype = 0;
            break;
    }

    if (pv->next_chapter_pts != AV_NOPTS_VALUE &&
        pv->next_chapter_pts <= pic_out->pts   &&
        pic_out->sliceType   == X265_TYPE_IDR)
    {
        // we're no longer looking for this chapter
        pv->next_chapter_pts = AV_NOPTS_VALUE;

        // get the chapter index from the list
        struct chapter_s *item = hb_list_item(pv->delayed_chapters, 0);
        if (item != NULL)
        {
            // we're done with this chapter
            hb_list_rem(pv->delayed_chapters, item);
            buf->s.new_chap = item->index;
            free(item);

            // we may still have another pending chapter
            item = hb_list_item(pv->delayed_chapters, 0);
            if (item != NULL)
            {
                // we're looking for this one now
                // we still need it, don't remove it
                pv->next_chapter_pts = item->start;
            }
        }
    }

    // discard empty buffers (no video)
    if (buf->size <= 0)
    {
        hb_buffer_close(&buf);
    }
    return buf;
}
Exemple #9
0
/***********************************************************************
 * ReaderFunc
 ***********************************************************************
 *
 **********************************************************************/
static void ReaderFunc( void * _r )
{
    hb_reader_t  * r = _r;
    hb_fifo_t   ** fifos;
    hb_buffer_t  * buf;
    hb_list_t    * list;
    int            n;
    int            chapter = -1;
    int            chapter_end = r->job->chapter_end;

    if ( r->title->type == HB_BD_TYPE )
    {
        if ( !( r->bd = hb_bd_init( r->title->path ) ) )
            return;
    }
    else if ( r->title->type == HB_DVD_TYPE )
    {
        if ( !( r->dvd = hb_dvd_init( r->title->path ) ) )
            return;
    }
    else if ( r->title->type == HB_STREAM_TYPE ||
              r->title->type == HB_FF_STREAM_TYPE )
    {
        if ( !( r->stream = hb_stream_open( r->title->path, r->title ) ) )
            return;
    }
    else
    {
        // Unknown type, should never happen
        return;
    }

    if (r->bd)
    {
        if( !hb_bd_start( r->bd, r->title ) )
        {
            hb_bd_close( &r->bd );
            return;
        }
        if ( r->job->start_at_preview )
        {
            // XXX code from DecodePreviews - should go into its own routine
            hb_bd_seek( r->bd, (float)r->job->start_at_preview /
                         ( r->job->seek_points ? ( r->job->seek_points + 1.0 ) : 11.0 ) );
        }
        else if ( r->job->pts_to_start )
        {
            // Note, bd seeks always put us to an i-frame.  no need
            // to start decoding early using r->pts_to_start
            hb_bd_seek_pts( r->bd, r->job->pts_to_start );
            r->job->pts_to_start = 0;
            r->start_found = 1;
        }
        else
        {
            hb_bd_seek_chapter( r->bd, r->job->chapter_start );
        }
        if (r->job->angle > 1)
        {
            hb_bd_set_angle( r->bd, r->job->angle - 1 );
        }
    }
    else if (r->dvd)
    {
        /*
         * XXX this code is a temporary hack that should go away if/when
         *     chapter merging goes away in libhb/dvd.c
         * map the start and end chapter numbers to on-media chapter
         * numbers since chapter merging could cause the handbrake numbers
         * to diverge from the media numbers and, if our chapter_end is after
         * a media chapter that got merged, we'll stop ripping too early.
         */
        int start = r->job->chapter_start;
        hb_chapter_t *chap = hb_list_item( r->title->list_chapter, chapter_end - 1 );

        chapter_end = chap->index;
        if (start > 1)
        {
           chap = hb_list_item( r->title->list_chapter, start - 1 );
           start = chap->index;
        }
        /* end chapter mapping XXX */

        if( !hb_dvd_start( r->dvd, r->title, start ) )
        {
            hb_dvd_close( &r->dvd );
            return;
        }
        if (r->job->angle)
        {
            hb_dvd_set_angle( r->dvd, r->job->angle );
        }

        if ( r->job->start_at_preview )
        {
            // XXX code from DecodePreviews - should go into its own routine
            hb_dvd_seek( r->dvd, (float)r->job->start_at_preview /
                         ( r->job->seek_points ? ( r->job->seek_points + 1.0 ) : 11.0 ) );
        }
    }
    else if ( r->stream && r->job->start_at_preview )
    {
        
        // XXX code from DecodePreviews - should go into its own routine
        hb_stream_seek( r->stream, (float)( r->job->start_at_preview - 1 ) /
                        ( r->job->seek_points ? ( r->job->seek_points + 1.0 ) : 11.0 ) );

    } 
    else if ( r->stream && r->job->pts_to_start )
    {
        int64_t pts_to_start = r->job->pts_to_start;
        
        // Find out what the first timestamp of the stream is
        // and then seek to the appropriate offset from it
        if ( ( buf = hb_stream_read( r->stream ) ) )
        {
            if ( buf->start > 0 )
            {
                pts_to_start += buf->start;
                r->pts_to_start += buf->start;
                r->job->pts_to_start += buf->start;
            }
        }
        
        if ( hb_stream_seek_ts( r->stream, pts_to_start ) >= 0 )
        {
            // Seek takes us to the nearest I-frame before the timestamp
            // that we want.  So we will retrieve the start time of the
            // first packet we get, subtract that from pts_to_start, and
            // inspect the reset of the frames in sync.
            r->start_found = 2;
            r->job->pts_to_start = pts_to_start;
        }
    } 
    else if( r->stream )
    {
        /*
         * Standard stream, seek to the starting chapter, if set, and track the
         * end chapter so that we end at the right time.
         */
        int start = r->job->chapter_start;
        hb_chapter_t *chap = hb_list_item( r->title->list_chapter, chapter_end - 1 );
        
        chapter_end = chap->index;
        if (start > 1)
        {
            chap = hb_list_item( r->title->list_chapter, start - 1 );
            start = chap->index;
        }
        
        /*
         * Seek to the start chapter.
         */
        hb_stream_seek_chapter( r->stream, start );
    }

    list  = hb_list_init();

    while( !*r->die && !r->job->done )
    {
        if (r->bd)
            chapter = hb_bd_chapter( r->bd );
        else if (r->dvd)
            chapter = hb_dvd_chapter( r->dvd );
        else if (r->stream)
            chapter = hb_stream_chapter( r->stream );

        if( chapter < 0 )
        {
            hb_log( "reader: end of the title reached" );
            break;
        }
        if( chapter > chapter_end )
        {
            hb_log( "reader: end of chapter %d (media %d) reached at media chapter %d",
                    r->job->chapter_end, chapter_end, chapter );
            break;
        }

        if (r->bd)
        {
          if( (buf = hb_bd_read( r->bd )) == NULL )
          {
              break;
          }
        }
        else if (r->dvd)
        {
          if( (buf = hb_dvd_read( r->dvd )) == NULL )
          {
              break;
          }
        }
        else if (r->stream)
        {
          if ( (buf = hb_stream_read( r->stream )) == NULL )
          {
            break;
          }
          if ( r->start_found == 2 )
          {
            // We will inspect the timestamps of each frame in sync
            // to skip from this seek point to the timestamp we
            // want to start at.
            if ( buf->start > 0 && buf->start < r->job->pts_to_start )
            {
                r->job->pts_to_start -= buf->start;
            }
            else if ( buf->start >= r->job->pts_to_start )
            {
                r->job->pts_to_start = 0;
                r->start_found = 1;
            }
          }
        }

        if( r->job->indepth_scan )
        {
            /*
             * Need to update the progress during a subtitle scan
             */
            hb_state_t state;

#define p state.param.working

            state.state = HB_STATE_WORKING;
            p.progress = (double)chapter / (double)r->job->chapter_end;
            if( p.progress > 1.0 )
            {
                p.progress = 1.0;
            }
            p.rate_avg = 0.0;
            p.hours    = -1;
            p.minutes  = -1;
            p.seconds  = -1;
            hb_set_state( r->job->h, &state );
        }

        (hb_demux[r->title->demuxer])( buf, list, &r->demux );

        while( ( buf = hb_list_item( list, 0 ) ) )
        {
            hb_list_rem( list, buf );
            fifos = GetFifoForId( r->job, buf->id );

            if ( fifos && ! r->saw_video && !r->job->indepth_scan )
            {
                // The first data packet with a PTS from an audio or video stream
                // that we're decoding defines 'time zero'. Discard packets until
                // we get one.
                if ( buf->start != -1 && buf->renderOffset != -1 &&
                     ( buf->id == r->title->video_id || is_audio( r, buf->id ) ) )
                {
                    // force a new scr offset computation
                    r->scr_changes = r->demux.scr_changes - 1;
                    // create a stream state if we don't have one so the
                    // offset will get computed correctly.
                    id_to_st( r, buf, 1 );
                    r->saw_video = 1;
                    hb_log( "reader: first SCR %"PRId64" id 0x%x DTS %"PRId64,
                            r->demux.last_scr, buf->id, buf->renderOffset );
                }
                else
                {
                    fifos = NULL;
                }
            }
            if( fifos )
            {
                if ( buf->renderOffset != -1 )
                {
                    if ( r->scr_changes != r->demux.scr_changes )
                    {
                        // This is the first audio or video packet after an SCR
                        // change. Compute a new scr offset that would make this
                        // packet follow the last of this stream with the 
                        // correct average spacing.
                        stream_timing_t *st = id_to_st( r, buf, 0 );

                        // if this is the video stream and we don't have
                        // audio yet or this is an audio stream
                        // generate a new scr
                        if ( st->is_audio ||
                             ( st == r->stream_timing && !r->saw_audio ) )
                        {
                            new_scr_offset( r, buf );
                        }
                        else
                        {
                            // defer the scr change until we get some
                            // audio since audio has a timestamp per
                            // frame but video & subtitles don't. Clear
                            // the timestamps so the decoder will generate
                            // them from the frame durations.
                            buf->start = -1;
                            buf->renderOffset = -1;
                        }
                    }
                }
                if ( buf->start != -1 )
                {
                    int64_t start = buf->start - r->scr_offset;
                    if ( !r->start_found )
                        UpdateState( r, start );

                    if ( !r->start_found &&
                        start >= r->pts_to_start )
                    {
                        // pts_to_start point found
                        r->start_found = 1;
                    }
                    // This log is handy when you need to debug timing problems
                    //hb_log("id %x scr_offset %ld start %ld --> %ld", 
                    //        buf->id, r->scr_offset, buf->start, 
                    //        buf->start - r->scr_offset);
                    buf->start -= r->scr_offset;
                }
                if ( buf->renderOffset != -1 )
                {
                    if ( r->scr_changes == r->demux.scr_changes )
                    {
                        // This packet is referenced to the same SCR as the last.
                        // Adjust timestamp to remove the System Clock Reference
                        // offset then update the average inter-packet time
                        // for this stream.
                        buf->renderOffset -= r->scr_offset;
                        update_ipt( r, buf );
                    }
                }
                if ( !r->start_found )
                {
                    hb_buffer_close( &buf );
                    continue;
                }

                buf->sequence = r->sequence++;
                /* if there are mutiple output fifos, send a copy of the
                 * buffer down all but the first (we have to not ship the
                 * original buffer or we'll race with the thread that's
                 * consuming the buffer & inject garbage into the data stream). */
                for( n = 1; fifos[n] != NULL; n++)
                {
                    hb_buffer_t *buf_copy = hb_buffer_init( buf->size );
                    hb_buffer_copy_settings( buf_copy, buf );
                    memcpy( buf_copy->data, buf->data, buf->size );
                    push_buf( r, fifos[n], buf_copy );
                }
                push_buf( r, fifos[0], buf );
            }
            else
            {
                hb_buffer_close( &buf );
            }
        }
    }

    // send empty buffers downstream to video & audio decoders to signal we're done.
    if( !*r->die && !r->job->done )
    {
        push_buf( r, r->job->fifo_mpeg2, hb_buffer_init(0) );

        hb_audio_t *audio;
        for( n = 0; (audio = hb_list_item( r->job->title->list_audio, n)); ++n )
        {
            if ( audio->priv.fifo_in )
                push_buf( r, audio->priv.fifo_in, hb_buffer_init(0) );
        }

        hb_subtitle_t *subtitle;
        for( n = 0; (subtitle = hb_list_item( r->job->title->list_subtitle, n)); ++n )
        {
            if ( subtitle->fifo_in && subtitle->source == VOBSUB)
                push_buf( r, subtitle->fifo_in, hb_buffer_init(0) );
        }
    }

    hb_list_empty( &list );
    if (r->bd)
    {
        hb_bd_stop( r->bd );
        hb_bd_close( &r->bd );
    }
    else if (r->dvd)
    {
        hb_dvd_stop( r->dvd );
        hb_dvd_close( &r->dvd );
    }
    else if (r->stream)
    {
        hb_stream_close(&r->stream);
    }

    if ( r->stream_timing )
    {
        free( r->stream_timing );
    }

    hb_log( "reader: done. %d scr changes", r->demux.scr_changes );
    if ( r->demux.dts_drops )
    {
        hb_log( "reader: %d drops because DTS out of range", r->demux.dts_drops );
    }

    free( r );
    _r = NULL;
}
Exemple #10
0
static void ScanFunc( void * _data )
{
    hb_scan_t  * data = (hb_scan_t *) _data;
    hb_title_t * title;
    int          i;
    int          feature = 0;

    data->bd = NULL;
    data->dvd = NULL;
    data->stream = NULL;

    /* Try to open the path as a DVD. If it fails, try as a file */
    if( ( data->bd = hb_bd_init( data->h, data->path ) ) )
    {
        hb_log( "scan: BD has %d title(s)",
                hb_bd_title_count( data->bd ) );
        if( data->title_index )
        {
            /* Scan this title only */
            hb_list_add( data->title_set->list_title,
                         hb_bd_title_scan( data->bd,
                         data->title_index, 0 ) );
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_bd_title_count( data->bd ); i++ )
            {
                UpdateState1(data, i + 1);
                hb_list_add( data->title_set->list_title,
                             hb_bd_title_scan( data->bd,
                             i + 1, data->min_title_duration ) );
            }
            feature = hb_bd_main_feature( data->bd,
                                          data->title_set->list_title );
        }
    }
    else if( ( data->dvd = hb_dvd_init( data->h, data->path ) ) )
    {
        hb_log( "scan: DVD has %d title(s)",
                hb_dvd_title_count( data->dvd ) );
        if( data->title_index )
        {
            /* Scan this title only */
            hb_list_add( data->title_set->list_title,
                         hb_dvd_title_scan( data->dvd,
                            data->title_index, 0 ) );
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ )
            {
                UpdateState1(data, i + 1);
                hb_list_add( data->title_set->list_title,
                             hb_dvd_title_scan( data->dvd,
                            i + 1, data->min_title_duration ) );
            }
            feature = hb_dvd_main_feature( data->dvd,
                                           data->title_set->list_title );
        }
    }
    else if ( ( data->batch = hb_batch_init( data->h, data->path ) ) )
    {
        if( data->title_index )
        {
            /* Scan this title only */
            title = hb_batch_title_scan(data->batch, data->title_index, 0);
            if ( title )
            {
                hb_list_add( data->title_set->list_title, title );
            }
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_batch_title_count( data->batch ); i++ )
            {
                hb_title_t * title;

                UpdateState1(data, i + 1);
                title = hb_batch_title_scan(data->batch, i + 1,
                                            data->min_title_duration);
                if ( title != NULL )
                {
                    hb_list_add( data->title_set->list_title, title );
                }
            }
        }
    }
    else
    {
        // Title index 0 is not a valid title number and means scan all titles.
        // So set title index to 1 in this scenario.
        //
        // Otherwise, set title index in new title to the index that was
        // requested.  This preserves the original index created in batch
        // mode.
        if (data->title_index == 0)
            data->title_index = 1;
        hb_title_t * title = hb_title_init( data->path, data->title_index );
        data->stream = hb_stream_open(data->h, data->path, title, 1);
        if (data->stream != NULL)
        {
            title = hb_stream_title_scan( data->stream, title );
            if ( title )
                hb_list_add( data->title_set->list_title, title );
        }
        else
        {
            hb_title_close( &title );
            hb_log( "scan: unrecognized file type" );
            goto finish;
        }
    }

    for( i = 0; i < hb_list_count( data->title_set->list_title ); )
    {
        int j, npreviews;
        hb_audio_t * audio;

        if ( *data->die )
        {
            goto finish;
        }
        title = hb_list_item( data->title_set->list_title, i );

        UpdateState2(data, i + 1);

        /* Decode previews */
        /* this will also detect more AC3 / DTS information */
        npreviews = DecodePreviews( data, title, 1 );
        if (npreviews < 2)
        {
            // Try harder to get some valid frames
            // Allow libav to return "corrupt" frames
            hb_log("scan: Too few previews (%d), trying harder", npreviews);
            title->flags |= HBTF_NO_IDR;
            npreviews = DecodePreviews( data, title, 0 );
        }
        if (npreviews == 0)
        {
            /* TODO: free things */
            hb_list_rem( data->title_set->list_title, title );
            for( j = 0; j < hb_list_count( title->list_audio ); j++)
            {
                audio = hb_list_item( title->list_audio, j );
                if ( audio->priv.scan_cache )
                {
                    hb_fifo_flush( audio->priv.scan_cache );
                    hb_fifo_close( &audio->priv.scan_cache );
                }
            }
            hb_title_close( &title );
            continue;
        }
        title->preview_count = npreviews;

        /* Make sure we found audio rates and bitrates */
        for( j = 0; j < hb_list_count( title->list_audio ); )
        {
            audio = hb_list_item( title->list_audio, j );
            if ( audio->priv.scan_cache )
            {
                hb_fifo_flush( audio->priv.scan_cache );
                hb_fifo_close( &audio->priv.scan_cache );
            }
            if( !audio->config.in.bitrate )
            {
                hb_log( "scan: removing audio 0x%x because no bitrate found",
                        audio->id );
                hb_list_rem( title->list_audio, audio );
                free( audio );
                continue;
            }
            j++;
        }

        // VOBSUB and PGS width and height needs to be set to the
        // title width and height for any stream type that does
        // not provide this information (DVDs, BDs, VOBs, and M2TSs).
        // Title width and height don't get set until we decode
        // previews, so we can't set subtitle width/height till
        // we get here.
        for (j = 0; j < hb_list_count(title->list_subtitle); j++)
        {
            hb_subtitle_t *subtitle = hb_list_item(title->list_subtitle, j);
            if ((subtitle->source == VOBSUB || subtitle->source == PGSSUB) &&
                (subtitle->width <= 0 || subtitle->height <= 0))
            {
                subtitle->width  = title->geometry.width;
                subtitle->height = title->geometry.height;
            }
        }
        i++;
    }

    data->title_set->feature = feature;

    /* Mark title scan complete and init jobs */
    for( i = 0; i < hb_list_count( data->title_set->list_title ); i++ )
    {
        title      = hb_list_item( data->title_set->list_title, i );
        title->flags |= HBTF_SCAN_COMPLETE;
    }
    if (hb_list_count(data->title_set->list_title) > 0)
    {
        strncpy(data->title_set->path, data->path, 1024);
        data->title_set->path[1023] = 0;
    }
    else
    {
        data->title_set->path[0] = 0;
    }

finish:

    if( data->bd )
    {
        hb_bd_close( &data->bd );
    }
    if( data->dvd )
    {
        hb_dvd_close( &data->dvd );
    }
    if (data->stream)
    {
        hb_stream_close(&data->stream);
    }
    if( data->batch )
    {
        hb_batch_close( &data->batch );
    }
    free( data->path );
    free( data );
    _data = NULL;
    hb_buffer_pool_free();
}
Exemple #11
0
static void ScanFunc( void * _data )
{
    hb_scan_t  * data = (hb_scan_t *) _data;
    hb_title_t * title;
    int          i;
    int          feature = 0;

    data->bd = NULL;
    data->dvd = NULL;
    data->stream = NULL;

    /* Try to open the path as a DVD. If it fails, try as a file */
    if( ( data->bd = hb_bd_init( data->path ) ) )
    {
        hb_log( "scan: BD has %d title(s)",
                hb_bd_title_count( data->bd ) );
        if( data->title_index )
        {
            /* Scan this title only */
            hb_list_add( data->list_title, hb_bd_title_scan( data->bd,
                         data->title_index, 0 ) );
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_bd_title_count( data->bd ); i++ )
            {
                hb_list_add( data->list_title, hb_bd_title_scan( data->bd, 
                             i + 1, data->min_title_duration ) );
            }
            feature = hb_bd_main_feature( data->bd, data->list_title );
        }
    }
    else if( ( data->dvd = hb_dvd_init( data->path ) ) )
    {
        hb_log( "scan: DVD has %d title(s)",
                hb_dvd_title_count( data->dvd ) );
        if( data->title_index )
        {
            /* Scan this title only */
            hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd,
                            data->title_index, 0 ) );
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ )
            {
                hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, 
                            i + 1, data->min_title_duration ) );
            }
            feature = hb_dvd_main_feature( data->dvd, data->list_title );
        }
    }
    else if ( ( data->batch = hb_batch_init( data->path ) ) )
    {
        if( data->title_index )
        {
            /* Scan this title only */
            title = hb_batch_title_scan( data->batch, data->title_index );
            if ( title )
            {
                hb_list_add( data->list_title, title );
            }
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_batch_title_count( data->batch ); i++ )
            {
                hb_title_t * title;

                title = hb_batch_title_scan( data->batch, i + 1 );
                if ( title != NULL )
                {
                    hb_list_add( data->list_title, title );
                }
            }
        }
    }
    else
    {
        hb_title_t * title = hb_title_init( data->path, 0 );
        if ( (data->stream = hb_stream_open( data->path, title, 1 ) ) != NULL )
        {
            title = hb_stream_title_scan( data->stream, title );
            if ( title )
                hb_list_add( data->list_title, title );
        }
        else
        {
            hb_title_close( &title );
            hb_log( "scan: unrecognized file type" );
            return;
        }
    }

    for( i = 0; i < hb_list_count( data->list_title ); )
    {
        int j;
        hb_state_t state;
        hb_audio_t * audio;

        if ( *data->die )
        {
            goto finish;
        }
        title = hb_list_item( data->list_title, i );

#define p state.param.scanning
        /* Update the UI */
        state.state   = HB_STATE_SCANNING;
        p.title_cur   = title->index;
        p.title_count = data->dvd ? hb_dvd_title_count( data->dvd ) : 
                        data->bd ? hb_bd_title_count( data->bd ) :
                        data->batch ? hb_batch_title_count( data->batch ) :
                                   hb_list_count(data->list_title);
        hb_set_state( data->h, &state );
#undef p

        /* Decode previews */
        /* this will also detect more AC3 / DTS information */
        if( !DecodePreviews( data, title ) )
        {
            /* TODO: free things */
            hb_list_rem( data->list_title, title );
            for( j = 0; j < hb_list_count( title->list_audio ); j++)
            {
                audio = hb_list_item( title->list_audio, j );
                if ( audio->priv.scan_cache )
                {
                    hb_fifo_flush( audio->priv.scan_cache );
                    hb_fifo_close( &audio->priv.scan_cache );
                }
            }
            hb_title_close( &title );
            continue;
        }

        /* Make sure we found audio rates and bitrates */
        for( j = 0; j < hb_list_count( title->list_audio ); )
        {
            audio = hb_list_item( title->list_audio, j );
            if ( audio->priv.scan_cache )
            {
                hb_fifo_flush( audio->priv.scan_cache );
                hb_fifo_close( &audio->priv.scan_cache );
            }
            if( !audio->config.in.bitrate )
            {
                hb_log( "scan: removing audio 0x%x because no bitrate found",
                        audio->id );
                hb_list_rem( title->list_audio, audio );
                free( audio );
                continue;
            }
            j++;
        }

        if ( data->dvd || data->bd )
        {
            // The subtitle width and height needs to be set to the 
            // title widht and height for DVDs.  title width and
            // height don't get set until we decode previews, so
            // we can't set subtitle width/height till we get here.
            for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
            {
                hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, j );
                if ( subtitle->source == VOBSUB || subtitle->source == PGSSUB )
                {
                    subtitle->width = title->width;
                    subtitle->height = title->height;
                }
            }
        }
        i++;
    }

    /* Init jobs templates */
    for( i = 0; i < hb_list_count( data->list_title ); i++ )
    {
        hb_job_t * job;

        title      = hb_list_item( data->list_title, i );
        job        = calloc( sizeof( hb_job_t ), 1 );
        title->job = job;

        job->title = title;
        job->feature = feature;

        /* Set defaults settings */
        job->chapter_start = 1;
        job->chapter_end   = hb_list_count( title->list_chapter );

        /* Autocrop by default. Gnark gnark */
        memcpy( job->crop, title->crop, 4 * sizeof( int ) );

        /* Preserve a source's pixel aspect, if it's available. */
        if( title->pixel_aspect_width && title->pixel_aspect_height )
        {
            job->anamorphic.par_width  = title->pixel_aspect_width;
            job->anamorphic.par_height = title->pixel_aspect_height;
        }

        if( title->aspect != 0 && title->aspect != 1. &&
            !job->anamorphic.par_width && !job->anamorphic.par_height)
        {
            hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height,
                       (int)(title->aspect * title->height + 0.5), title->width );
        }

        job->width = title->width - job->crop[2] - job->crop[3];
        hb_fix_aspect( job, HB_KEEP_WIDTH );
        if( job->height > title->height - job->crop[0] - job->crop[1] )
        {
            job->height = title->height - job->crop[0] - job->crop[1];
            hb_fix_aspect( job, HB_KEEP_HEIGHT );
        }

        hb_log( "scan: title (%d) job->width:%d, job->height:%d",
                i, job->width, job->height );

        job->keep_ratio = 1;

        job->vcodec     = HB_VCODEC_FFMPEG_MPEG4;
        job->vquality   = -1.0;
        job->vbitrate   = 1000;
        job->pass       = 0;
        job->vrate      = title->rate;
        job->vrate_base = title->rate_base;

        job->list_audio = hb_list_init();
        job->list_subtitle = hb_list_init();
        job->list_filter = hb_list_init();

        job->mux = HB_MUX_MP4;
    }

finish:

    if( data->bd )
    {
        hb_bd_close( &data->bd );
    }
    if( data->dvd )
    {
        hb_dvd_close( &data->dvd );
    }
    if (data->stream)
    {
        hb_stream_close(&data->stream);
    }
    if( data->batch )
    {
        hb_batch_close( &data->batch );
    }
    free( data->path );
    free( data );
    _data = NULL;
}
Exemple #12
0
/***********************************************************************
 * DecodePreviews
 ***********************************************************************
 * Decode 10 pictures for the given title.
 * It assumes that data->reader and data->vts have successfully been
 * DVDOpen()ed and ifoOpen()ed.
 **********************************************************************/
static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
{
    int             i, npreviews = 0;
    hb_buffer_t   * buf, * buf_es;
    hb_list_t     * list_es;
    int progressive_count = 0;
    int pulldown_count = 0;
    int doubled_frame_count = 0;
    int interlaced_preview_count = 0;
    info_list_t * info_list = calloc( data->preview_count+1, sizeof(*info_list) );
    crop_record_t *crops = crop_record_init( data->preview_count );

    list_es  = hb_list_init();

    if( data->batch )
    {
        hb_log( "scan: decoding previews for title %d (%s)", title->index, title->path );
    }
    else
    {
        hb_log( "scan: decoding previews for title %d", title->index );
    }

    if (data->bd)
    {
        hb_bd_start( data->bd, title );
        hb_log( "scan: title angle(s) %d", title->angle_count );
    }
    else if (data->dvd)
    {
        hb_dvd_start( data->dvd, title, 1 );
        title->angle_count = hb_dvd_angle_count( data->dvd );
        hb_log( "scan: title angle(s) %d", title->angle_count );
    }
    else if (data->batch)
    {
        data->stream = hb_stream_open( title->path, title, 1 );
    }

    int vcodec = title->video_codec? title->video_codec : WORK_DECMPEG2;
#if defined(USE_FF_MPEG2)
    if (vcodec == WORK_DECMPEG2)
    {
        vcodec = WORK_DECAVCODECV;
        title->video_codec_param = CODEC_ID_MPEG2VIDEO;
    }
#endif
    hb_work_object_t *vid_decoder = hb_get_work( vcodec );
    vid_decoder->codec_param = title->video_codec_param;
    vid_decoder->title = title;
    vid_decoder->init( vid_decoder, NULL );

    for( i = 0; i < data->preview_count; i++ )
    {
        int j;

        if ( *data->die )
        {
            free( info_list );
            crop_record_free( crops );
            return 0;
        }
        if (data->bd)
        {
            if( !hb_bd_seek( data->bd, (float) ( i + 1 ) / ( data->preview_count + 1.0 ) ) )
          {
              continue;
          }
        }
        if (data->dvd)
        {
            if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / ( data->preview_count + 1.0 ) ) )
          {
              continue;
          }
        }
        else if (data->stream)
        {
          /* we start reading streams at zero rather than 1/11 because
           * short streams may have only one sequence header in the entire
           * file and we need it to decode any previews. */
          if (!hb_stream_seek(data->stream, (float) i / ( data->preview_count + 1.0 ) ) )
          {
              continue;
          }
        }

        hb_deep_log( 2, "scan: preview %d", i + 1 );

        if ( vid_decoder->flush )
            vid_decoder->flush( vid_decoder );

        hb_buffer_t * vid_buf = NULL;

        for( j = 0; j < 10240 ; j++ )
        {
            if (data->bd)
            {
              if( (buf = hb_bd_read( data->bd )) == NULL )
              {
                  if ( vid_buf )
                  {
                    break;
                  }
                  hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                  goto skip_preview;
              }
            }
            else if (data->dvd)
            {
              if( (buf = hb_dvd_read( data->dvd )) == NULL )
              {
                  if ( vid_buf )
                  {
                    break;
                  }
                  hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                  goto skip_preview;
              }
            }
            else if (data->stream)
            {
              if ( (buf = hb_stream_read( data->stream )) == NULL )
              {
                  if ( vid_buf )
                  {
                    break;
                  }
                  hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                  goto skip_preview;
              }
            }
            else
            {
                // Silence compiler warning
                buf = NULL;
                hb_error( "Error: This can't happen!" );
                goto skip_preview;
            }

            (hb_demux[title->demuxer])(buf, list_es, 0 );

            while( ( buf_es = hb_list_item( list_es, 0 ) ) )
            {
                hb_list_rem( list_es, buf_es );
                if( buf_es->s.id == title->video_id && vid_buf == NULL )
                {
                    vid_decoder->work( vid_decoder, &buf_es, &vid_buf );
                }
                else if( ! AllAudioOK( title ) ) 
                {
                    LookForAudio( title, buf_es );
                    buf_es = NULL;
                }
                if ( buf_es )
                    hb_buffer_close( &buf_es );
            }

            if( vid_buf && AllAudioOK( title ) )
                break;
        }

        if( ! vid_buf )
        {
            hb_log( "scan: could not get a decoded picture" );
            continue;
        }

        /* Get size and rate infos */

        hb_work_info_t vid_info;
        if( !vid_decoder->info( vid_decoder, &vid_info ) )
        {
            /*
             * Could not fill vid_info, don't continue and try to use vid_info
             * in this case.
             */
            if (vid_buf)
            {
                hb_buffer_close( &vid_buf );
            }
            hb_log( "scan: could not get a video information" );
            continue;
        }

        remember_info( info_list, &vid_info );

        if( is_close_to( vid_info.rate_base, 900900, 100 ) &&
            ( vid_buf->s.flags & PIC_FLAG_REPEAT_FIRST_FIELD ) )
        {
            /* Potentially soft telecine material */
            pulldown_count++;
        }

        if( vid_buf->s.flags & PIC_FLAG_REPEAT_FRAME )
        {
            // AVCHD-Lite specifies that all streams are
            // 50 or 60 fps.  To produce 25 or 30 fps, camera
            // makers are repeating all frames.
            doubled_frame_count++;
        }

        if( is_close_to( vid_info.rate_base, 1126125, 100 ) )
        {
            // Frame FPS is 23.976 (meaning it's progressive), so start keeping
            // track of how many are reporting at that speed. When enough 
            // show up that way, we want to make that the overall title FPS.
            progressive_count++;
        }

        while( ( buf_es = hb_list_item( list_es, 0 ) ) )
        {
            hb_list_rem( list_es, buf_es );
            hb_buffer_close( &buf_es );
        }

        /* Check preview for interlacing artifacts */
        if( hb_detect_comb( vid_buf, 10, 30, 9, 10, 30, 9 ) )
        {
            hb_deep_log( 2, "Interlacing detected in preview frame %i", i+1);
            interlaced_preview_count++;
        }
        
        if( data->store_previews )
        {
            hb_save_preview( data->h, title->index, i, vid_buf );
        }

        /* Detect black borders */

        int top, bottom, left, right;
        int h4 = vid_info.height / 4, w4 = vid_info.width / 4;

        // When widescreen content is matted to 16:9 or 4:3 there's sometimes
        // a thin border on the outer edge of the matte. On TV content it can be
        // "line 21" VBI data that's normally hidden in the overscan. For HD
        // content it can just be a diagnostic added in post production so that
        // the frame borders are visible. We try to ignore these borders so
        // we can crop the matte. The border width depends on the resolution
        // (12 pixels on 1080i looks visually the same as 4 pixels on 480i)
        // so we allow the border to be up to 1% of the frame height.
        const int border = vid_info.height / 100;

        for ( top = border; top < h4; ++top )
        {
            if ( ! row_all_dark( vid_buf, top ) )
                break;
        }
        if ( top <= border )
        {
            // we never made it past the border region - see if the rows we
            // didn't check are dark or if we shouldn't crop at all.
            for ( top = 0; top < border; ++top )
            {
                if ( ! row_all_dark( vid_buf, top ) )
                    break;
            }
            if ( top >= border )
            {
                top = 0;
            }
        }
        for ( bottom = border; bottom < h4; ++bottom )
        {
            if ( ! row_all_dark( vid_buf, vid_info.height - 1 - bottom ) )
                break;
        }
        if ( bottom <= border )
        {
            for ( bottom = 0; bottom < border; ++bottom )
            {
                if ( ! row_all_dark( vid_buf, vid_info.height - 1 - bottom ) )
                    break;
            }
            if ( bottom >= border )
            {
                bottom = 0;
            }
        }
        for ( left = 0; left < w4; ++left )
        {
            if ( ! column_all_dark( vid_buf, top, bottom, left ) )
                break;
        }
        for ( right = 0; right < w4; ++right )
        {
            if ( ! column_all_dark( vid_buf, top, bottom, vid_info.width - 1 - right ) )
                break;
        }

        // only record the result if all the crops are less than a quarter of
        // the frame otherwise we can get fooled by frames with a lot of black
        // like titles, credits & fade-thru-black transitions.
        if ( top < h4 && bottom < h4 && left < w4 && right < w4 )
        {
            record_crop( crops, top, bottom, left, right );
        }
        ++npreviews;

skip_preview:
        /* Make sure we found audio rates and bitrates */
        for( j = 0; j < hb_list_count( title->list_audio ); j++ )
        {
            hb_audio_t * audio = hb_list_item( title->list_audio, j );
            if ( audio->priv.scan_cache )
            {
                hb_fifo_flush( audio->priv.scan_cache );
            }
        }
        if (vid_buf)
        {
            hb_buffer_close( &vid_buf );
        }
    }
    vid_decoder->close( vid_decoder );
    free( vid_decoder );

    if ( data->batch && data->stream )
    {
        hb_stream_close( &data->stream );
    }

    if ( npreviews )
    {
        // use the most common frame info for our final title dimensions
        hb_work_info_t vid_info;
        most_common_info( info_list, &vid_info );

        title->has_resolution_change = has_resolution_change( info_list );
        if ( title->video_codec_name == NULL )
        {
            title->video_codec_name = strdup( vid_info.name );
        }
        title->width = vid_info.width;
        title->height = vid_info.height;
        if ( vid_info.rate && vid_info.rate_base )
        {
            // if the frame rate is very close to one of our "common" framerates,
            // assume it actually is said frame rate; e.g. some 24000/1001 sources
            // may have a rate_base of 1126124 (instead of 1126125)
            for( i = 0; i < hb_video_rates_count; i++ )
            {
                if( is_close_to( vid_info.rate_base, hb_video_rates[i].rate, 100 ) )
                {
                    vid_info.rate_base = hb_video_rates[i].rate;
                    break;
                }
            }
            title->rate = vid_info.rate;
            title->rate_base = vid_info.rate_base;
            if( vid_info.rate_base == 900900 )
            {
                if( pulldown_count >= npreviews / 4 )
                {
                    title->rate_base = 1126125;
                    hb_deep_log( 2, "Pulldown detected, setting fps to 23.976" );
                }
                if( progressive_count >= npreviews / 2 )
                {
                    // We've already deduced that the frame rate is 23.976,
                    // so set it back again.
                    title->rate_base = 1126125;
                    hb_deep_log( 2, "Title's mostly NTSC Film, setting fps to 23.976" );
                }
            }
            if( doubled_frame_count >= 3 * npreviews / 4 )
            {
                // We've detected that a significant number of the frames
                // have been doubled in duration by repeat flags.
                title->rate_base = 2 * vid_info.rate_base;
                hb_deep_log( 2, "Repeat frames detected, setting fps to %.3f", (float)title->rate / title->rate_base );
            }
        }
        title->video_bitrate = vid_info.bitrate;

        if( vid_info.pixel_aspect_width && vid_info.pixel_aspect_height )
        {
            title->pixel_aspect_width = vid_info.pixel_aspect_width;
            title->pixel_aspect_height = vid_info.pixel_aspect_height;
        }
        title->color_prim = vid_info.color_prim;
        title->color_transfer = vid_info.color_transfer;
        title->color_matrix = vid_info.color_matrix;

        // compute the aspect ratio based on the storage dimensions and the
        // pixel aspect ratio (if supplied) or just storage dimensions if no PAR.
        title->aspect = (double)title->width / (double)title->height;
        title->aspect *= (double)title->pixel_aspect_width /
                         (double)title->pixel_aspect_height;

        // For unknown reasons some French PAL DVDs put the original
        // content's aspect ratio into the mpeg PAR even though it's
        // the wrong PAR for the DVD. Apparently they rely on the fact
        // that DVD players ignore the content PAR and just use the
        // aspect ratio from the DVD metadata. So, if the aspect computed
        // from the PAR is different from the container's aspect we use
        // the container's aspect & recompute the PAR from it.
        if( title->container_aspect && (int)(title->aspect * 9) != (int)(title->container_aspect * 9) )
        {
            hb_log("scan: content PAR gives wrong aspect %.2f; "
                   "using container aspect %.2f", title->aspect,
                   title->container_aspect );
            title->aspect = title->container_aspect;
            hb_reduce( &title->pixel_aspect_width, &title->pixel_aspect_height,
                       (int)(title->aspect * title->height + 0.5), title->width );
        }

        // don't try to crop unless we got at least 3 previews
        if ( crops->n > 2 )
        {
            sort_crops( crops );
            // The next line selects median cropping - at least
            // 50% of the frames will have their borders removed.
            // Other possible choices are loose cropping (i = 0) where 
            // no non-black pixels will be cropped from any frame and a
            // tight cropping (i = crops->n - (crops->n >> 2)) where at
            // least 75% of the frames will have their borders removed.
            i = crops->n >> 1;
            title->crop[0] = EVEN( crops->t[i] );
            title->crop[1] = EVEN( crops->b[i] );
            title->crop[2] = EVEN( crops->l[i] );
            title->crop[3] = EVEN( crops->r[i] );
        }

        hb_log( "scan: %d previews, %dx%d, %.3f fps, autocrop = %d/%d/%d/%d, "
                "aspect %s, PAR %d:%d",
                npreviews, title->width, title->height, (float) title->rate /
                (float) title->rate_base,
                title->crop[0], title->crop[1], title->crop[2], title->crop[3],
                aspect_to_string( title->aspect ), title->pixel_aspect_width,
                title->pixel_aspect_height );

        if( interlaced_preview_count >= ( npreviews / 2 ) )
        {
            hb_log("Title is likely interlaced or telecined (%i out of %i previews). You should do something about that.",
                   interlaced_preview_count, npreviews);
            title->detected_interlacing = 1;
        }
        else
        {
            title->detected_interlacing = 0;
        }
    }
Exemple #13
0
/***********************************************************************
 * DecodePreviews
 ***********************************************************************
 * Decode 10 pictures for the given title.
 * It assumes that data->reader and data->vts have successfully been
 * DVDOpen()ed and ifoOpen()ed.
 **********************************************************************/
static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
{
    int             i, npreviews = 0;
    hb_buffer_t   * buf_ps, * buf_es;
    hb_list_t     * list_es;
    int progressive_count = 0;
    int interlaced_preview_count = 0;
    info_list_t * info_list = calloc( data->preview_count+1, sizeof(*info_list) );
    crop_record_t *crops = calloc( 1, sizeof(*crops) );

    buf_ps   = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
    list_es  = hb_list_init();

    hb_log( "scan: decoding previews for title %d", title->index );

    if (data->bd)
    {
        hb_bd_start( data->bd, title );
        hb_log( "scan: title angle(s) %d", title->angle_count );
    }
    else if (data->dvd)
    {
        hb_dvd_start( data->dvd, title, 1 );
        title->angle_count = hb_dvd_angle_count( data->dvd );
        hb_log( "scan: title angle(s) %d", title->angle_count );
    }
    else if (data->batch)
    {
        data->stream = hb_stream_open( title->path, title );
    }

    for( i = 0; i < data->preview_count; i++ )
    {
        int j;
        FILE * file_preview;
        char   filename[1024];

        if ( *data->die )
        {
            return 0;
        }
        if (data->bd)
        {
            if( !hb_bd_seek( data->bd, (float) ( i + 1 ) / ( data->preview_count + 1.0 ) ) )
          {
              continue;
          }
        }
        if (data->dvd)
        {
            if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / ( data->preview_count + 1.0 ) ) )
          {
              continue;
          }
        }
        else if (data->stream)
        {
          /* we start reading streams at zero rather than 1/11 because
           * short streams may have only one sequence header in the entire
           * file and we need it to decode any previews. */
          if (!hb_stream_seek(data->stream, (float) i / ( data->preview_count + 1.0 ) ) )
          {
              continue;
          }
        }

        hb_deep_log( 2, "scan: preview %d", i + 1 );

        int vcodec = title->video_codec? title->video_codec : WORK_DECMPEG2;
#if defined(USE_FF_MPEG2)
        if (vcodec == WORK_DECMPEG2)
        {
            vcodec = WORK_DECAVCODECV;
            title->video_codec_param = CODEC_ID_MPEG2VIDEO;
        }
#endif
        hb_work_object_t *vid_decoder = hb_get_work( vcodec );
        vid_decoder->codec_param = title->video_codec_param;
        vid_decoder->title = title;
        vid_decoder->init( vid_decoder, NULL );
        hb_buffer_t * vid_buf = NULL;
        int vidskip = 0;

        if ( title->flags & HBTF_NO_IDR )
        {
            // title doesn't have IDR frames so we decode but drop one second's
            // worth of frames to allow the decoder to converge.
            if ( ! title->rate_base )
            {
                vidskip = 30;
            }
            else
            {
                vidskip = (double)title->rate / (double)title->rate_base + 0.5;
            }
            // If it's a BD, we can relax this a bit. Since seeks will
            // at least get us to a recovery point.
            if (data->bd)
                vidskip = 4;
        }

        for( j = 0; j < 10240 ; j++ )
        {
            if (data->bd)
            {
              if( !hb_bd_read( data->bd, buf_ps ) )
              {
                  if ( vid_buf )
                  {
                    break;
                  }
                  hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                  goto skip_preview;
              }
            }
            if (data->dvd)
            {
              if( !hb_dvd_read( data->dvd, buf_ps ) )
              {
                  if ( vid_buf )
                  {
                    break;
                  }
                  hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                  goto skip_preview;
              }
            }
            else if (data->stream)
            {
              if ( !hb_stream_read(data->stream,buf_ps) )
              {
                  if ( vid_buf )
                  {
                    break;
                  }
                  hb_log( "Warning: Could not read data for preview %d, skipped", i + 1 );
                  goto skip_preview;
              }
            }
            (hb_demux[title->demuxer])(buf_ps, list_es, 0 );

            while( ( buf_es = hb_list_item( list_es, 0 ) ) )
            {
                hb_list_rem( list_es, buf_es );
                if( buf_es->id == title->video_id && vid_buf == NULL )
                {
                    vid_decoder->work( vid_decoder, &buf_es, &vid_buf );
                    if ( vid_buf && vidskip && --vidskip > 0 )
                    {
                        // we're dropping frames to get the video decoder in sync
                        // when the video stream doesn't contain IDR frames
                        while (vid_buf && --vidskip >= 0)
                        {
                            hb_buffer_t * next = vid_buf->next;
                            vid_buf->next = NULL;
                            hb_buffer_close( &vid_buf );
                            vid_buf = next;
                        }
                    }
                }
                else if( ! AllAudioOK( title ) ) 
                {
                    LookForAudio( title, buf_es );
                    buf_es = NULL;
                }
                if ( buf_es )
                    hb_buffer_close( &buf_es );
            }

            if( vid_buf && AllAudioOK( title ) )
                break;
        }

        if( ! vid_buf )
        {
            hb_log( "scan: could not get a decoded picture" );
            continue;
        }

        /* Get size and rate infos */

        hb_work_info_t vid_info;
        if( !vid_decoder->info( vid_decoder, &vid_info ) )
        {
            /*
             * Could not fill vid_info, don't continue and try to use vid_info
             * in this case.
             */
            if (vid_buf)
            {
                hb_buffer_close( &vid_buf );
            }
            vid_decoder->close( vid_decoder );
            free( vid_decoder );
            continue;
        }
        vid_decoder->close( vid_decoder );
        free( vid_decoder );

        remember_info( info_list, &vid_info );

        title->video_codec_name = strdup( vid_info.name );
        title->width = vid_info.width;
        title->height = vid_info.height;
        title->rate = vid_info.rate;
        title->rate_base = vid_info.rate_base;
        title->video_bitrate = vid_info.bitrate;

        if( title->rate_base == 1126125 )
        {
            /* Frame FPS is 23.976 (meaning it's progressive), so
               start keeping track of how many are reporting at
               that speed. When enough show up that way, we want
               to make that the overall title FPS.
            */
            progressive_count++;

            if( progressive_count < 6 )
            {
                /* Not enough frames are reporting as progressive,
                   which means we should be conservative and use
                   29.97 as the title's FPS for now.
                */
                title->rate_base = 900900;
            }
            else
            {
                /* A majority of the scan frames are progressive. Make that
                    the title's FPS, and announce it once to the log.
                */
                if( progressive_count == 6 )
                {
                    hb_deep_log( 2, "Title's mostly NTSC Film, setting fps to 23.976");
                }
                title->rate_base = 1126125;
            }
        }
        else if( title->rate_base == 900900 && progressive_count >= 6 )
        {
            /*
             * We've already deduced that the frame rate is 23.976, so set it
             * back again.
             */
            title->rate_base = 1126125;
        }

        while( ( buf_es = hb_list_item( list_es, 0 ) ) )
        {
            hb_list_rem( list_es, buf_es );
            hb_buffer_close( &buf_es );
        }

        /* Check preview for interlacing artifacts */
        if( hb_detect_comb( vid_buf, title->width, title->height, 10, 30, 9, 10, 30, 9 ) )
        {
            hb_deep_log( 2, "Interlacing detected in preview frame %i", i+1);
            interlaced_preview_count++;
        }
        
        if( data->store_previews )
        {
            hb_get_tempory_filename( data->h, filename, "%d_%d_%d",
                                     hb_get_instance_id(data->h), title->index, i );

            file_preview = fopen( filename, "wb" );
            if( file_preview )
            {
                fwrite( vid_buf->data, title->width * title->height * 3 / 2,
                        1, file_preview );
                fclose( file_preview );
            }
            else
            {
                hb_log( "scan: fopen failed (%s)", filename );
            }
        }

        /* Detect black borders */

#define Y    vid_buf->data
        int top, bottom, left, right;
        int h4 = title->height / 4, w4 = title->width / 4;

        // When widescreen content is matted to 16:9 or 4:3 there's sometimes
        // a thin border on the outer edge of the matte. On TV content it can be
        // "line 21" VBI data that's normally hidden in the overscan. For HD
        // content it can just be a diagnostic added in post production so that
        // the frame borders are visible. We try to ignore these borders so
        // we can crop the matte. The border width depends on the resolution
        // (12 pixels on 1080i looks visually the same as 4 pixels on 480i)
        // so we allow the border to be up to 1% of the frame height.
        const int border = title->height / 100;

        for ( top = border; top < h4; ++top )
        {
            if ( ! row_all_dark( title, Y, top ) )
                break;
        }
        if ( top <= border )
        {
            // we never made it past the border region - see if the rows we
            // didn't check are dark or if we shouldn't crop at all.
            for ( top = 0; top < border; ++top )
            {
                if ( ! row_all_dark( title, Y, top ) )
                    break;
            }
            if ( top >= border )
            {
                top = 0;
            }
        }
        for ( bottom = border; bottom < h4; ++bottom )
        {
            if ( ! row_all_dark( title, Y, title->height - 1 - bottom ) )
                break;
        }
        if ( bottom <= border )
        {
            for ( bottom = 0; bottom < border; ++bottom )
            {
                if ( ! row_all_dark( title, Y, title->height - 1 - bottom ) )
                    break;
            }
            if ( bottom >= border )
            {
                bottom = 0;
            }
        }
        for ( left = 0; left < w4; ++left )
        {
            if ( ! column_all_dark( title, Y, top, bottom, left ) )
                break;
        }
        for ( right = 0; right < w4; ++right )
        {
            if ( ! column_all_dark( title, Y, top, bottom, title->width - 1 - right ) )
                break;
        }

        // only record the result if all the crops are less than a quarter of
        // the frame otherwise we can get fooled by frames with a lot of black
        // like titles, credits & fade-thru-black transitions.
        if ( top < h4 && bottom < h4 && left < w4 && right < w4 )
        {
            record_crop( crops, top, bottom, left, right );
        }
        ++npreviews;

skip_preview:
        /* Make sure we found audio rates and bitrates */
        for( j = 0; j < hb_list_count( title->list_audio ); j++ )
        {
            hb_audio_t * audio = hb_list_item( title->list_audio, j );
            if ( audio->priv.scan_cache )
            {
                hb_fifo_flush( audio->priv.scan_cache );
            }
        }
        if (vid_buf)
        {
            hb_buffer_close( &vid_buf );
        }
    }

    if ( data->batch && data->stream )
    {
        hb_stream_close( &data->stream );
    }

    if ( npreviews )
    {
        // use the most common frame info for our final title dimensions
        hb_work_info_t vid_info;
        most_common_info( info_list, &vid_info );

        title->width = vid_info.width;
        title->height = vid_info.height;
        title->pixel_aspect_width = vid_info.pixel_aspect_width;
        title->pixel_aspect_height = vid_info.pixel_aspect_height;

        // compute the aspect ratio based on the storage dimensions and the
        // pixel aspect ratio (if supplied) or just storage dimensions if no PAR.
        title->aspect = (double)title->width / (double)title->height;
        if( title->pixel_aspect_width && title->pixel_aspect_height )
        {
            title->aspect *= (double)title->pixel_aspect_width /
                             (double)title->pixel_aspect_height;

            // For unknown reasons some French PAL DVDs put the original
            // content's aspect ratio into the mpeg PAR even though it's
            // the wrong PAR for the DVD. Apparently they rely on the fact
            // that DVD players ignore the content PAR and just use the
            // aspect ratio from the DVD metadata. So, if the aspect computed
            // from the PAR is different from the container's aspect we use
            // the container's aspect & recompute the PAR from it.
            if( title->container_aspect && (int)(title->aspect * 9) != (int)(title->container_aspect * 9) )
            {
                hb_log("scan: content PAR gives wrong aspect %.2f; "
                       "using container aspect %.2f", title->aspect,
                       title->container_aspect );
                title->aspect = title->container_aspect;
                hb_reduce( &title->pixel_aspect_width, &title->pixel_aspect_height,
                           (int)(title->aspect * title->height + 0.5), title->width );
            }
        }

        // don't try to crop unless we got at least 3 previews
        if ( crops->n > 2 )
        {
            sort_crops( crops );
            // The next line selects median cropping - at least
            // 50% of the frames will have their borders removed.
            // Other possible choices are loose cropping (i = 0) where 
            // no non-black pixels will be cropped from any frame and a
            // tight cropping (i = crops->n - (crops->n >> 2)) where at
            // least 75% of the frames will have their borders removed.
            i = crops->n >> 1;
            title->crop[0] = EVEN( crops->t[i] );
            title->crop[1] = EVEN( crops->b[i] );
            title->crop[2] = EVEN( crops->l[i] );
            title->crop[3] = EVEN( crops->r[i] );
        }
        free( crops );

        hb_log( "scan: %d previews, %dx%d, %.3f fps, autocrop = %d/%d/%d/%d, "
                "aspect %s, PAR %d:%d",
                npreviews, title->width, title->height, (float) title->rate /
                (float) title->rate_base,
                title->crop[0], title->crop[1], title->crop[2], title->crop[3],
                aspect_to_string( title->aspect ), title->pixel_aspect_width,
                title->pixel_aspect_height );

        if( interlaced_preview_count >= ( npreviews / 2 ) )
        {
            hb_log("Title is likely interlaced or telecined (%i out of %i previews). You should do something about that.",
                   interlaced_preview_count, npreviews);
            title->detected_interlacing = 1;
        }
        else
        {
            title->detected_interlacing = 0;
        }
    }
Exemple #14
0
static void ScanFunc( void * _data )
{
    hb_scan_t  * data = (hb_scan_t *) _data;
    hb_title_t * title;
    int          i;
    int          feature = 0;

    data->bd = NULL;
    data->dvd = NULL;
    data->stream = NULL;

    /* Try to open the path as a DVD. If it fails, try as a file */
    if( ( data->bd = hb_bd_init( data->path ) ) )
    {
        hb_log( "scan: BD has %d title(s)",
                hb_bd_title_count( data->bd ) );
        if( data->title_index )
        {
            /* Scan this title only */
            hb_list_add( data->title_set->list_title,
                         hb_bd_title_scan( data->bd,
                         data->title_index, 0 ) );
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_bd_title_count( data->bd ); i++ )
            {
                UpdateState1(data, i + 1);
                hb_list_add( data->title_set->list_title,
                             hb_bd_title_scan( data->bd, 
                             i + 1, data->min_title_duration ) );
            }
            feature = hb_bd_main_feature( data->bd,
                                          data->title_set->list_title );
        }
    }
    else if( ( data->dvd = hb_dvd_init( data->path ) ) )
    {
        hb_log( "scan: DVD has %d title(s)",
                hb_dvd_title_count( data->dvd ) );
        if( data->title_index )
        {
            /* Scan this title only */
            hb_list_add( data->title_set->list_title,
                         hb_dvd_title_scan( data->dvd,
                            data->title_index, 0 ) );
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ )
            {
                UpdateState1(data, i + 1);
                hb_list_add( data->title_set->list_title,
                             hb_dvd_title_scan( data->dvd, 
                            i + 1, data->min_title_duration ) );
            }
            feature = hb_dvd_main_feature( data->dvd,
                                           data->title_set->list_title );
        }
    }
    else if ( ( data->batch = hb_batch_init( data->path ) ) )
    {
        if( data->title_index )
        {
            /* Scan this title only */
            title = hb_batch_title_scan( data->batch, data->title_index );
            if ( title )
            {
                hb_list_add( data->title_set->list_title, title );
            }
        }
        else
        {
            /* Scan all titles */
            for( i = 0; i < hb_batch_title_count( data->batch ); i++ )
            {
                hb_title_t * title;

                UpdateState1(data, i + 1);
                title = hb_batch_title_scan( data->batch, i + 1 );
                if ( title != NULL )
                {
                    hb_list_add( data->title_set->list_title, title );
                }
            }
        }
    }
    else
    {
        data->title_index = 1;
        hb_title_t * title = hb_title_init( data->path, data->title_index );
        if ( (data->stream = hb_stream_open( data->path, title, 1 ) ) != NULL )
        {
            title = hb_stream_title_scan( data->stream, title );
            if ( title )
                hb_list_add( data->title_set->list_title, title );
        }
        else
        {
            hb_title_close( &title );
            hb_log( "scan: unrecognized file type" );
            return;
        }
    }

    for( i = 0; i < hb_list_count( data->title_set->list_title ); )
    {
        int j;
        hb_audio_t * audio;

        if ( *data->die )
        {
            goto finish;
        }
        title = hb_list_item( data->title_set->list_title, i );

        UpdateState2(data, i + 1);

        /* Decode previews */
        /* this will also detect more AC3 / DTS information */
        if( !DecodePreviews( data, title ) )
        {
            /* TODO: free things */
            hb_list_rem( data->title_set->list_title, title );
            for( j = 0; j < hb_list_count( title->list_audio ); j++)
            {
                audio = hb_list_item( title->list_audio, j );
                if ( audio->priv.scan_cache )
                {
                    hb_fifo_flush( audio->priv.scan_cache );
                    hb_fifo_close( &audio->priv.scan_cache );
                }
            }
            hb_title_close( &title );
            continue;
        }

        /* Make sure we found audio rates and bitrates */
        for( j = 0; j < hb_list_count( title->list_audio ); )
        {
            audio = hb_list_item( title->list_audio, j );
            if ( audio->priv.scan_cache )
            {
                hb_fifo_flush( audio->priv.scan_cache );
                hb_fifo_close( &audio->priv.scan_cache );
            }
            if( !audio->config.in.bitrate )
            {
                hb_log( "scan: removing audio 0x%x because no bitrate found",
                        audio->id );
                hb_list_rem( title->list_audio, audio );
                free( audio );
                continue;
            }
            j++;
        }

        if ( data->dvd || data->bd )
        {
            // The subtitle width and height needs to be set to the 
            // title widht and height for DVDs.  title width and
            // height don't get set until we decode previews, so
            // we can't set subtitle width/height till we get here.
            for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
            {
                hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, j );
                if ( subtitle->source == VOBSUB || subtitle->source == PGSSUB )
                {
                    subtitle->width = title->width;
                    subtitle->height = title->height;
                }
            }
        }
        i++;
    }

    data->title_set->feature = feature;

    /* Mark title scan complete and init jobs */
    for( i = 0; i < hb_list_count( data->title_set->list_title ); i++ )
    {
        title      = hb_list_item( data->title_set->list_title, i );
        title->flags |= HBTF_SCAN_COMPLETE;
#if defined(HB_TITLE_JOBS)
        title->job = hb_job_init( title );
#endif
    }

finish:

    if( data->bd )
    {
        hb_bd_close( &data->bd );
    }
    if( data->dvd )
    {
        hb_dvd_close( &data->dvd );
    }
    if (data->stream)
    {
        hb_stream_close(&data->stream);
    }
    if( data->batch )
    {
        hb_batch_close( &data->batch );
    }
    free( data->path );
    free( data );
    _data = NULL;
    hb_buffer_pool_free();
}