tlRender
tlRender copied to clipboard
Audio starts late
A commit made the audio start late. When the audio was added with the -a
b476f32b5d121fec19615a125e8853512ac9c0de
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.
I checked in a fix for this, could you sync to the latest main and see if it works OK with your test files?
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 @.***
Thanks for testing it out!