Esempio n. 1
0
static uint32_t seek_video
(
    lwlibav_video_decode_handler_t *vdhp,
    AVFrame                        *picture,
    uint32_t                        presentation_sample_number,
    uint32_t                        rap_number,
    int64_t                         rap_pos,
    int                             error_ignorance
)
{
    /* Prepare to decode from random accessible sample. */
    lwlibav_extradata_handler_t *exhp = &vdhp->exh;
    int extradata_index = vdhp->frame_list[rap_number].extradata_index;
    if( extradata_index != exhp->current_index )
        /* Update the decoder configuration. */
        lwlibav_update_configuration( (lwlibav_decode_handler_t *)vdhp, rap_number, extradata_index, rap_pos );
    else
        lwlibav_flush_buffers( (lwlibav_decode_handler_t *)vdhp );
    if( vdhp->error )
        return 0;
    if( av_seek_frame( vdhp->format, vdhp->stream_index, rap_pos, vdhp->av_seek_flags ) < 0 )
        av_seek_frame( vdhp->format, vdhp->stream_index, rap_pos, vdhp->av_seek_flags | AVSEEK_FLAG_ANY );
    int      got_picture = 0;
    int64_t  rap_pts = AV_NOPTS_VALUE;
    uint32_t current;
    uint32_t decoder_delay = get_decoder_delay( vdhp->ctx );
    uint32_t thread_delay  = decoder_delay - vdhp->ctx->has_b_frames;
    uint32_t goal = presentation_sample_number + decoder_delay;
    exhp->delay_count     = 0;
    vdhp->last_half_frame = 0;
    for( current = rap_number; current <= goal; current++ )
    {
        int ret = decode_video_picture( vdhp, picture, &got_picture, &current, goal, rap_number );
        if( ret == -2 )
            return 0;
        else if( ret >= 1 )
        {
            /* No decoding occurs. */
            got_picture = 0;
            break;
        }
        /* Handle decoder delay derived from PAFF field coded pictures. */
        if( current <= vdhp->frame_count && current >= rap_number + decoder_delay
         && !got_picture && vdhp->frame_list[current].repeat_pict == 0 )
        {
            /* No output picture since the second field coded picture of the next frame is not decoded yet. */
            if( decoder_delay - thread_delay < 2 * vdhp->ctx->has_b_frames + 1UL )
            {
                uint32_t new_decoder_delay = thread_delay + 2 * vdhp->ctx->has_b_frames + 1UL;
                goal += new_decoder_delay - decoder_delay;
                decoder_delay = new_decoder_delay;
            }
        }
        if( got_picture )
        {
            exhp->delay_count = MIN( decoder_delay, current - rap_number );
            uint32_t frame_number = current - exhp->delay_count;
            vdhp->last_half_frame = (frame_number <= vdhp->frame_count && vdhp->frame_list[frame_number].repeat_pict == 0);
        }
        /* Some decoders return -1 when feeding a leading sample.
         * We don't consider as an error if the return value -1 is caused by a leading sample since it's not fatal at all. */
        if( current == vdhp->last_rap_number && picture->pts != AV_NOPTS_VALUE )
            rap_pts = picture->pts;
        if( ret == -1 && (picture->pts == AV_NOPTS_VALUE || picture->pts >= rap_pts) && !error_ignorance )
        {
            if( vdhp->lh.show_log )
                vdhp->lh.show_log( &vdhp->lh, LW_LOG_ERROR, "Failed to decode a video frame." );
            return 0;
        }
    }
    exhp->delay_count = MIN( decoder_delay, current - rap_number );
    if( current > rap_number && vdhp->last_half_frame )
    {
        if( got_picture )
            /* first field of PAFF field coded picture */
            vdhp->last_half_offset = 0;
        else
        {
            /* second field of PAFF field coded picture */
            vdhp->last_half_frame  = UINT32_MAX;
            vdhp->last_half_offset = 1;     /* A picture of the second field is already decoded. */
        }
    }
    else
    {
        vdhp->last_half_frame  = 0;
        vdhp->last_half_offset = 0;
    }
    return current;
}
Esempio n. 2
0
uint64_t lwlibav_audio_get_pcm_samples
(
    lwlibav_audio_decode_handler_t *adhp,
    lwlibav_audio_output_handler_t *aohp,
    void                           *buf,
    int64_t                         start,
    int64_t                         wanted_length
)
{
    if( adhp->error )
        return 0;
    uint32_t               frame_number;
    uint32_t               rap_number      = 0;
    uint32_t               past_rap_number = 0;
    uint64_t               output_length   = 0;
    enum audio_output_flag output_flags    = AUDIO_OUTPUT_NO_FLAGS;
    AVPacket              *pkt       = &adhp->packet;
    AVPacket              *alter_pkt = &adhp->alter_packet;
    int                    already_gotten;
    aohp->request_length = wanted_length;
    if( start > 0 && start == adhp->next_pcm_sample_number )
    {
        frame_number   = adhp->last_frame_number;
        output_length += output_pcm_samples_from_buffer( aohp, adhp->frame_buffer, (uint8_t **)&buf, &output_flags );
        if( output_flags & AUDIO_OUTPUT_ENOUGH )
            goto audio_out;
        if( alter_pkt->size <= 0 )
            ++frame_number;
        aohp->output_sample_offset = 0;
        already_gotten             = 0;
    }
    else
    {
        /* Seek audio stream. */
        adhp->next_pcm_sample_number = 0;
        adhp->last_frame_number      = 0;
        /* Get frame_number. */
        uint64_t start_frame_pos;
        if( start >= 0 )
            start_frame_pos = start;
        else
        {
            uint64_t silence_length = -start;
            put_silence_audio_samples( (int)(silence_length * aohp->output_block_align), aohp->output_bits_per_sample == 8, (uint8_t **)&buf );
            output_length        += silence_length;
            aohp->request_length -= silence_length;
            start_frame_pos = 0;
        }
        frame_number = find_start_audio_frame( adhp, aohp->output_sample_rate, start_frame_pos, &aohp->output_sample_offset );
retry_seek:
        av_packet_unref( pkt );
        /* Flush audio resampler buffers. */
        if( flush_resampler_buffers( aohp->avr_ctx ) < 0 )
        {
            adhp->error = 1;
            lw_log_show( &adhp->lh, LW_LOG_FATAL,
                         "Failed to flush resampler buffers.\n"
                         "It is recommended you reopen the file." );
            return 0;
        }
        /* Flush audio decoder buffers. */
        lwlibav_extradata_handler_t *exhp = &adhp->exh;
        int extradata_index = adhp->frame_list[frame_number].extradata_index;
        if( extradata_index != exhp->current_index )
        {
            /* Update the extradata. */
            rap_number = get_audio_rap( adhp, frame_number );
            assert( rap_number != 0 );
            lwlibav_update_configuration( (lwlibav_decode_handler_t *)adhp, rap_number, extradata_index, 0 );
        }
        else
            lwlibav_flush_buffers( (lwlibav_decode_handler_t *)adhp );
        if( adhp->error )
            return 0;
        /* Seek and get a audio packet. */
        rap_number = seek_audio( adhp, frame_number, past_rap_number, pkt, output_flags != AUDIO_OUTPUT_NO_FLAGS ? adhp->frame_buffer : NULL );
        already_gotten = 1;
    }
    do
    {
        if( already_gotten )
        {
            already_gotten = 0;
            make_decodable_packet( alter_pkt, pkt );
        }
        else if( frame_number > adhp->frame_count )
        {
            av_packet_unref( pkt );
            if( adhp->exh.delay_count || !(output_flags & AUDIO_OUTPUT_ENOUGH) )
            {
                /* Null packet */
                av_init_packet( pkt );
                make_null_packet( pkt );
                *alter_pkt = *pkt;
                if( adhp->exh.delay_count )
                    adhp->exh.delay_count -= 1;
            }
            else
                goto audio_out;
        }
        else if( alter_pkt->size <= 0 )
        {
            /* Getting an audio packet must be after flushing all remaining samples in resampler's FIFO buffer. */
            lwlibav_get_av_frame( adhp->format, adhp->stream_index, frame_number, pkt );
            make_decodable_packet( alter_pkt, pkt );
        }
        /* Decode and output from an audio packet. */
        output_flags   = AUDIO_OUTPUT_NO_FLAGS;
        output_length += output_pcm_samples_from_packet( aohp, adhp->ctx, alter_pkt, adhp->frame_buffer, (uint8_t **)&buf, &output_flags );
        if( output_flags & AUDIO_DECODER_DELAY )
        {
            if( rap_number > 1 && (output_flags & AUDIO_DECODER_ERROR) )
            {
                /* Retry to seek from more past audio keyframe because libavformat might have failed seek.
                 * This operation occurs only at the first decoding time after seek. */
                past_rap_number = get_audio_rap( adhp, rap_number - 1 );
                if( past_rap_number
                 && past_rap_number < rap_number )
                    goto retry_seek;
            }
            ++ adhp->exh.delay_count;
        }
        else
            /* Disable seek retry. */
            rap_number = 0;
        if( output_flags & AUDIO_RECONFIG_FAILURE )
        {
            adhp->error = 1;
            lw_log_show( &adhp->lh, LW_LOG_FATAL,
                         "Failed to reconfigure resampler.\n"
                         "It is recommended you reopen the file." );
            goto audio_out;
        }
        if( output_flags & AUDIO_OUTPUT_ENOUGH )
            goto audio_out;
        if( output_flags & (AUDIO_DECODER_ERROR | AUDIO_DECODER_RECEIVED_PACKET) )
            ++frame_number;
    } while( 1 );
audio_out:
    adhp->next_pcm_sample_number = start + output_length;
    adhp->last_frame_number      = frame_number;
    return output_length;
}
void lwlibav_update_configuration
(
    lwlibav_decode_handler_t *dhp,
    uint32_t                  frame_number,
    int                       extradata_index,
    int64_t                   rap_pos
)
{
    lwlibav_extradata_handler_t *exhp = &dhp->exh;
    if( exhp->entry_count == 0 || extradata_index < 0 )
    {
        /* No need to update the extradata. */
        exhp->current_index = extradata_index;
        lwlibav_flush_buffers( dhp );
        return;
    }
    AVCodecContext *ctx = dhp->format->streams[ dhp->stream_index ]->codec;
    void *app_specific = ctx->opaque;
    avcodec_close( ctx );
    if( ctx->extradata )
    {
        av_freep( &ctx->extradata );
        ctx->extradata_size = 0;
    }
    /* Find an appropriate decoder. */
    char error_string[96] = { 0 };
    lwlibav_extradata_t *entry = &exhp->entries[extradata_index];
    const AVCodec *codec = find_decoder( entry->codec_id, dhp->preferred_decoder_names );
    if( !codec )
    {
        strcpy( error_string, "Failed to find the decoder.\n" );
        goto fail;
    }
    /* Get decoder default settings. */
    int thread_count = ctx->thread_count;
    if( avcodec_get_context_defaults3( ctx, codec ) < 0 )
    {
        strcpy( error_string, "Failed to get CODEC default.\n" );
        goto fail;
    }
    /* Set up decoder basic settings. */
    if( ctx->codec_type == AVMEDIA_TYPE_VIDEO )
        set_video_basic_settings( dhp, frame_number );
    else
        set_audio_basic_settings( dhp, frame_number );
    /* Update extradata. */
    if( entry->extradata_size > 0 )
    {
        ctx->extradata = (uint8_t *)av_malloc( entry->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE );
        if( !ctx->extradata )
        {
            strcpy( error_string, "Failed to allocate extradata.\n" );
            goto fail;
        }
        ctx->extradata_size = entry->extradata_size;
        memcpy( ctx->extradata, entry->extradata, ctx->extradata_size );
        memset( ctx->extradata + ctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE );
    }
    /* AVCodecContext.codec_id is supposed to be set properly in avcodec_open2().
     * See lwlibav_flush_buffers(), why this is needed. */
    ctx->codec_id  = AV_CODEC_ID_NONE;
    /* This is needed by some CODECs such as UtVideo and raw video. */
    ctx->codec_tag = entry->codec_tag;
    /* Open an appropriate decoder.
     * Here, we force single threaded decoding since some decoder doesn't do its proper initialization with multi-threaded decoding. */
    ctx->thread_count = 1;
    if( open_decoder( ctx, codec ) < 0 )
    {
        strcpy( error_string, "Failed to open decoder.\n" );
        goto fail;
    }
    exhp->current_index = extradata_index;
    exhp->delay_count   = 0;
    /* Set up decoder basic settings by actual decoding. */
    if( ctx->codec_type == AVMEDIA_TYPE_VIDEO
      ? try_decode_video_frame( dhp, frame_number, rap_pos, error_string ) < 0
      : try_decode_audio_frame( dhp, frame_number, error_string ) < 0 )
        goto fail;
    /* Reopen/flush with the requested number of threads. */
    ctx->thread_count = thread_count;
    int width  = ctx->width;
    int height = ctx->height;
    lwlibav_flush_buffers( dhp );
    ctx->get_buffer2 = exhp->get_buffer ? exhp->get_buffer : avcodec_default_get_buffer2;
    ctx->opaque      = app_specific;
    /* avcodec_open2() may have changed resolution unexpectedly. */
    ctx->width       = width;
    ctx->height      = height;
    return;
fail:
    exhp->delay_count = 0;
    dhp->error = 1;
    lw_log_show( &dhp->lh, LW_LOG_FATAL,
                 "%sIt is recommended you reopen the file.", error_string );
}