Opened 6 years ago

Closed 5 years ago

#1831 closed defect (fixed)

Seeking by byte returns success but does not seek

Reported by: mbradshaw Owned by:
Priority: normal Component: avformat
Version: git-master Keywords: seek
Cc: Blocked By:
Blocking: Reproduced by developer: yes
Analyzed by developer: no

Description (last modified by mbradshaw)

Summary of the bug:
When calling av_seek_frame() (or avformat_seek_file()) with AVSEEK_FLAG_BYTE, it returns 0 indicating success, however, the seek is not performed. I have attached a file that exposes this failure, though I have many files for which this problem occurs.

How to reproduce:
I created the below quick sample code to show that seeking by byte does not work. If you change the seeking flag to AVSEEK_FLAG_BACKWARD then it works as expected. In both cases, however, av_seek_frame() returns 0, indicating success.

#include <iostream>

extern "C"
{
#include <avcodec.h>
#include <avformat.h>
#include <swscale.h>
};

int main()
{
    av_register_all();

    AVFrame* frame = avcodec_alloc_frame();
    if (!frame)
    {
        std::cout << "Error allocating the frame" << std::endl;
        return 1;
    }

    AVFormatContext* formatContext = NULL;
    if (avformat_open_input(&formatContext, "C:/Users/mbradshaw/Desktop/b/MP4-MC264-AAC.mp4", NULL, NULL) != 0)
    {
        av_free(frame);
        std::cout << "Error opening the file" << std::endl;
        return 1;
    }

    if (avformat_find_stream_info(formatContext, NULL) < 0)
    {
        av_free(frame);
        av_close_input_file(formatContext);
        std::cout << "Error finding the stream info" << std::endl;
        return 1;
    }

    AVStream* audioStream = NULL;
    for (unsigned int i = 0; i < formatContext->nb_streams; ++i)
    {
        if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioStream = formatContext->streams[i];
            break;
        }
    }

    if (audioStream == NULL)
    {
        av_free(frame);
        av_close_input_file(formatContext);
        std::cout << "Could not find any audio stream in the file" << std::endl;
        return 1;
    }

    AVCodecContext* codecContext = audioStream->codec;

    codecContext->codec = avcodec_find_decoder(codecContext->codec_id);
    if (codecContext->codec == NULL)
    {
        av_free(frame);
        av_close_input_file(formatContext);
        std::cout << "Couldn't find a proper decoder" << std::endl;
        return 1;
    }
    else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)
    {
        av_free(frame);
        av_close_input_file(formatContext);
        std::cout << "Couldn't open the context with the decoder" << std::endl;
        return 1;
    }

    AVPacket packet;
    av_init_packet(&packet);

    int packetCount = 0;
    int decodedFrameCount = 0;
    while (av_read_frame(formatContext, &packet) == 0)
    {
        ++packetCount;
        if (packet.stream_index == audioStream->index)
        {
            int frameFinished = 0;
            avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet);

            if (frameFinished)
            {
                ++decodedFrameCount;
            }
        }

        av_free_packet(&packet);
    }

    std::cout << "packetCount: " << packetCount << "\tdecodedFrameCount: " << decodedFrameCount << std::endl;
    std::cout << "formatContext->iformat->flags: " << formatContext->iformat->flags << "\tno byte seeking: " << (formatContext->iformat->flags & AVFMT_NO_BYTE_SEEK) << std::endl;

    avcodec_flush_buffers(codecContext);
    av_init_packet(&packet);
    std::cout << "av_seek_frame() returned: " << av_seek_frame(formatContext, -1, 0, AVSEEK_FLAG_BYTE) << std::endl;
    
    packetCount = 0;
    decodedFrameCount = 0;
    while (av_read_frame(formatContext, &packet) == 0)
    {
        ++packetCount;
        if (packet.stream_index == audioStream->index)
        {
            // Try to decode the packet into a frame
            int frameFinished = 0;
            avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet);

            if (frameFinished)
            {
                ++decodedFrameCount;
            }
        }

        av_free_packet(&packet);
    }

    std::cout << "packetCount: " << packetCount << "\tdecodedFrameCount: " << decodedFrameCount << std::endl;

    av_free(frame);
    avcodec_close(codecContext);
    av_close_input_file(formatContext);
}

Actual results:

packetCount: 526        decodedFrameCount: 259
formatContext->iformat->flags: 0        no byte seeking: 0
av_seek_frame() returned: 0
packetCount: 0  decodedFrameCount: 0

Expected results: (if seeking really does succeed)

packetCount: 526        decodedFrameCount: 259
formatContext->iformat->flags: 0        no byte seeking: 0
av_seek_frame() returned: 0
packetCount: 526        decodedFrameCount: 259

Alternative expected results: (if seeking really does fail because byte seeking is not allowed)

packetCount: 526        decodedFrameCount: 259
formatContext->iformat->flags: 32768        no byte seeking: 32768
av_seek_frame() returned: -1
packetCount: 0        decodedFrameCount: 0

Attachments (1)

MP4-MC264-AAC.mp4 (1.4 MB) - added by mbradshaw 6 years ago.

Download all attachments as: .zip

Change History (7)

Changed 6 years ago by mbradshaw

comment:1 Changed 6 years ago by mbradshaw

  • Component changed from undetermined to avformat
  • Description modified (diff)

Reformatted the sample code (tabs to spaces), fixed a small typo, and set compenent to avformat.

comment:2 Changed 6 years ago by mbradshaw

  • Description modified (diff)

Another typo fix, sorry.

comment:3 follow-up: Changed 6 years ago by cehoyos

  • Keywords seek added

Could you confirm that you see the same behaviour with current git head?

comment:4 in reply to: ↑ 3 Changed 6 years ago by mbradshaw

Replying to cehoyos:

Could you confirm that you see the same behaviour with current git head?

Yes, I can confirm this is reproducible with current git head. I just tried it with the latest code. Same thing.

comment:5 Changed 6 years ago by mbradshaw

  • Version changed from 1.0 to git-master

comment:6 Changed 5 years ago by michael

  • Reproduced by developer set
  • Resolution set to fixed
  • Status changed from new to closed

Reproduced with ffplay instead

Note: See TracTickets for help on using tickets.