tlRender icon indicating copy to clipboard operation
tlRender copied to clipboard

Audio starts late

Open ggarra13 opened this issue 2 years ago • 1 comments

A commit made the audio start late. When the audio was added with the -a flag, all was still good. I didn't do a bisect, but audio was fine at least up to:

b476f32b5d121fec19615a125e8853512ac9c0de

ggarra13 avatar Aug 17 '22 00:08 ggarra13

I do see this with the movie you sent me, it looks like it happens with movies that have a timecode offset. I'll look into it.

darbyjohnston avatar Aug 19 '22 20:08 darbyjohnston

I checked in a fix for this, could you sync to the latest main and see if it works OK with your test files?

darbyjohnston avatar Dec 18 '22 23:12 darbyjohnston

El 18 dic. 2022, a las 20:40, Darby Johnston @.***> escribió:

I checked in a fix for this, could you sync to the latest main and see if it works OK with your test files?

Seems to fix it.

Here Is.the isimplified code and routines from mrViewer 1 ’s aviImage.cpp that extract all the audio info:

struct StreamInfo
{
    const AVFormatContext* context;
    int          stream_index;
    bool         play;
    bool         has_codec;
    bool         closed_captions;
    std::string  codec_name;
    std::string  fourcc;
    std::string  language;
    std::string  disposition;
    double       start;
    double       duration;

    StreamInfo() : context( NULL ),
                   stream_index(-1),
                   play( true ),
                   has_codec(false),
                   closed_captions( false ),
                   start(0),
                   duration(0)
    {
    }

};

struct AudioStream : public StreamInfo { unsigned int channels; unsigned int frequency; unsigned int bitrate; std::string format;

    AudioStream() : StreamInfo(), channels(0), frequency(0), bitrate(0)
    {
    }

    AudioStream( const AudioStream& b ) :
        StreamInfo( b ),
        channels( b.channels ),
        frequency( b.frequency ),
        bitrate( b.bitrate ),
        format( b.format )
    {
    }
};
typedef AudioStream audio_info_t;

———————————————————————————————————————————————————————————————————————————————————————

// Iterate through all the streams available
for( unsigned i = 0; i < _context->nb_streams; ++i )
{
    // Get the codec context
    AVStream* stream = _context->streams[ i ];

    if ( stream == NULL ) continue;

    const AVCodecParameters* par = stream->codecpar;
    if ( par == NULL ) continue;

    AVCodecContext* ctx = avcodec_alloc_context3( NULL );
    if (!ctx )
    {
        LOG_ERROR( _("Not enough memory for context" ) );
        continue;
    }
    int err = avcodec_parameters_to_context( ctx, par );
    if ( err < 0 )
    {
        LOG_ERROR( _("Could not copy parameters to context") );
        continue;
    }

    // Determine the type and obtain the first index of each type
    switch( ctx->codec_type )
    {
    // We ignore attachments for now.
    case AVMEDIA_TYPE_ATTACHMENT:
    {
        stream->discard = AVDISCARD_ALL;
        continue;
    }
    // We ignore data tracks for now.  Data tracks are, for example,
    // the timecode track in quicktimes.
    case AVMEDIA_TYPE_DATA:
    {
        stream->discard = AVDISCARD_ALL;
        continue;
    }
    case AVMEDIA_TYPE_VIDEO:
    {
      // … you already have this nailed
        break;
    }
    case AVMEDIA_TYPE_AUDIO:
    {
        audio_info_t s;
        populate_stream_info( s, msg, _context, par, i );

#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 33, 100) s.channels = par->ch_layout.nb_channels; #else s.channels = par->channels; #endif s.frequency = par->sample_rate; s.bitrate = calculate_bitrate( stream, par );

        const char* fmt = av_get_sample_fmt_name( ctx->sample_fmt );
        if ( fmt ) s.format = fmt;

        _audio_info.push_back( s );
        if ( _audio_index < 0 && s.has_codec )
        {
            DBGM1("Audio Stream #" << _audio_info.size() << " found" );
            _audio_index = _audio_info.size()-1;
        }
        break;
    }
    case AVMEDIA_TYPE_SUBTITLE:
    {
        subtitle_info_t s;
        populate_stream_info( s, msg, _context, par, i );
        s.closed_captions = !!( ctx->properties &
                                FF_CODEC_PROPERTY_CLOSED_CAPTIONS);
        s.bitrate    = calculate_bitrate( stream, par );
        _subtitle_info.push_back( s );
        if ( _subtitle_index < 0 )
        {
            _subtitle_index = _subtitle_info.size()-1;
            DBGM1("Subtitle Stream #" << _subtitle_info.size()
                  << " found" );
        }
        break;
    }
    default:
    {
        const char* stream = stream_type( ctx );
        msg << _("\n\nNot a known stream type for stream #")
            << i << (", type ") << stream;
        break;
    }
    }

    avcodec_free_context( &ctx );
}

———————————————————————————————————————————————————————————————————————————————— /**

  • Returns the FFMPEG stream index of current audio channel.
  • @return */ int CMedia::audio_stream_index() const { if ( _audio_index < 0 ) return -1; // Muted assert( _audio_index >= 0 ); assert( unsigned(_audio_index) < _audio_info.size()); return _audio_info[ _audio_index ].stream_index; }

// Returns the current audio stream AVStream* CMedia::get_audio_stream() const { if ( _audio_index < 0 ) return NULL; // Muted if ( _audio_info[ _audio_index ].context == NULL ) return NULL;

return _audio_info[ _audio_index ].context->streams[ audio_stream_index() ];

}

// Opens the audio codec associated to the current stream void CMedia::open_audio_codec() { AVStream *stream = get_audio_stream(); if ( stream == NULL ) return;

AVCodecParameters* cpar = stream->codecpar;
if ( cpar == NULL )
{
    IMG_ERROR( _("No codec context for audio stream.") );
    _audio_index = -1;
    return;
}

_audio_codec = (AVCodec*)avcodec_find_decoder( cpar->codec_id );
if ( _audio_codec == NULL )
{
    IMG_ERROR( _("No decoder found for audio stream. ID: ")
               << cpar->codec_id );
    _audio_index = -1;
    return;
}

_audio_ctx = avcodec_alloc_context3(_audio_codec);
int r = avcodec_parameters_to_context(_audio_ctx, cpar);
if ( r < 0 )
{
    LOG_ERROR( _("avcodec_copy_context failed for audio") );
    _audio_index = -1;
    return;
}

_audio_ctx->pkt_timebase = get_audio_stream()->time_base;

AVDictionary* opts = NULL;

if ( avcodec_open2( _audio_ctx, _audio_codec, &opts ) < 0 )
{
    IMG_ERROR( _("Could not open audio codec.") );
    _audio_index = -1;
}

frequency = _audio_ctx->sample_rate;

…etc... }

— Gonzalo Garramuno @.***

ggarra13 avatar Dec 19 '22 02:12 ggarra13

Thanks for testing it out!

darbyjohnston avatar Dec 19 '22 03:12 darbyjohnston