Skip to content

Commit

Permalink
scan: limit errors during audio scan (HandBrake#6003)
Browse files Browse the repository at this point in the history
If the number of errors received while attempting to decode an audio
track exceeds a limit, drop the audio track.

Fixes HandBrake#5242
  • Loading branch information
jstebbins authored Apr 27, 2024
1 parent d0685b9 commit 21405b6
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 33 deletions.
17 changes: 11 additions & 6 deletions libhb/decavcodec.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,12 +905,13 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
unsigned char *parse_buffer;
int parse_pos, parse_buffer_size;

int avcodec_result = 0;
while (buf != NULL && !done)
{
parse_pos = 0;
while (parse_pos < buf->size && !done)
{
int parse_len, ret;
int parse_len;

if (parser != NULL)
{
Expand All @@ -937,8 +938,8 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
avp->pts = buf->s.start;
avp->dts = AV_NOPTS_VALUE;

ret = avcodec_send_packet(context, avp);
if (ret < 0 && ret != AVERROR_EOF)
avcodec_result = avcodec_send_packet(context, avp);
if (avcodec_result < 0 && avcodec_result != AVERROR_EOF)
{
parse_pos += parse_len;
av_packet_free(&avp);
Expand All @@ -952,8 +953,8 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
{
frame = av_frame_alloc();
}
ret = avcodec_receive_frame(context, frame);
if (ret >= 0)
avcodec_result = avcodec_receive_frame(context, frame);
if (avcodec_result >= 0)
{
// libavcoded doesn't consistently set frame->sample_rate
if (frame->sample_rate != 0)
Expand Down Expand Up @@ -1056,7 +1057,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
av_frame_unref(frame);
break;
}
} while (ret >= 0);
} while (avcodec_result >= 0);
av_packet_free(&avp);
av_frame_free(&frame);
parse_pos += parse_len;
Expand All @@ -1071,6 +1072,10 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
if ( parser != NULL )
av_parser_close( parser );
hb_avcodec_free_context(&context);
if (!result && avcodec_result < 0 && avcodec_result != AVERROR_EOF)
{
result = avcodec_result;
}
return result;
}

Expand Down
1 change: 1 addition & 0 deletions libhb/handbrake/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,7 @@ struct hb_audio_s

hb_mux_data_t * mux_data;
hb_fifo_t * scan_cache;
int scan_error_count;
} priv;
};
#endif
Expand Down
67 changes: 40 additions & 27 deletions libhb/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ typedef struct
} hb_scan_t;

#define PREVIEW_READ_THRESH (200)
#define AUDIO_DECODE_ERROR_LIMIT (10)

static void ScanFunc( void * );
static int DecodePreviews( hb_scan_t *, hb_title_t * title, int flush );
static void LookForAudio(hb_scan_t *scan, hb_title_t *title, hb_buffer_t *b);
static hb_audio_t * find_audio_for_id(hb_title_t * title, int id);
static void LookForAudio(hb_scan_t *scan, hb_title_t *title, hb_audio_t * audio, hb_buffer_t *b);
static int AllAudioOK( hb_title_t * title );
static void UpdateState1(hb_scan_t *scan, int title);
static void UpdateState2(hb_scan_t *scan, int title);
Expand Down Expand Up @@ -1041,8 +1043,12 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
}
else if (!AllAudioOK(title) && !abort_audio)
{
LookForAudio( data, title, buf_es );
buf_es = NULL;
hb_audio_t * audio = find_audio_for_id(title, buf_es->s.id);
if (audio != NULL && audio->priv.scan_error_count < AUDIO_DECODE_ERROR_LIMIT)
{
LookForAudio( data, title, audio, buf_es );
buf_es = NULL;
}
}
if ( buf_es )
hb_buffer_close( &buf_es );
Expand Down Expand Up @@ -1537,6 +1543,23 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
return npreviews;
}

static hb_audio_t * find_audio_for_id(hb_title_t * title, int id)
{
int i;
hb_audio_t * audio = NULL;

for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
audio = hb_list_item( title->list_audio, i );
/* check if this elementary stream is one we want */
if ( audio->id == id )
{
return audio;
}
}
return NULL;
}

/*
* This routine is called for every frame from a non-video elementary stream.
* These are a mix of audio & subtitle streams, some of which we want & some
Expand All @@ -1551,24 +1574,8 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
* aren't (e.g., some European DVD Teletext streams use the same IDs as US ATSC
* AC-3 audio).
*/
static void LookForAudio(hb_scan_t *scan, hb_title_t * title, hb_buffer_t * b)
static void LookForAudio(hb_scan_t *scan, hb_title_t * title, hb_audio_t * audio, hb_buffer_t * b)
{
int i;

hb_audio_t * audio = NULL;
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
audio = hb_list_item( title->list_audio, i );
/* check if this elementary stream is one we want */
if ( audio->id == b->s.id )
{
break;
}
else
{
audio = NULL;
}
}
if( !audio || audio->config.in.bitrate != 0 )
{
/* not found or already done */
Expand Down Expand Up @@ -1602,16 +1609,22 @@ static void LookForAudio(hb_scan_t *scan, hb_title_t * title, hb_buffer_t * b)
w->codec_param = audio->config.in.codec_param;
b = hb_fifo_see( audio->priv.scan_cache );
int ret = w->bsinfo( w, b, &info );
if ( ret < 0 )
if ( ret < 0 && ret != AVERROR(EAGAIN) )
{
hb_log( "no info on audio type %d/0x%x for id 0x%x",
audio->config.in.codec, audio->config.in.codec_param,
audio->id );
goto drop_audio;
// No point in attempting to decode the
// same data again the next time around
hb_buffer_t * tmp;
tmp = hb_fifo_get( audio->priv.scan_cache );
hb_buffer_close( &tmp );
free( w );
audio->priv.scan_error_count++;
return;
}
if ( !info.bitrate )
{
/* didn't find any info */
// didn't find any info
// Additional buffer data may be required to obtain
// audio attributes
free( w );
return;
}
Expand Down Expand Up @@ -1875,7 +1888,7 @@ static int AllAudioOK( hb_title_t * title )
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
audio = hb_list_item( title->list_audio, i );
if( audio->config.in.bitrate == 0 )
if ( audio->priv.scan_error_count < AUDIO_DECODE_ERROR_LIMIT && audio->config.in.bitrate == 0 )
{
return 0;
}
Expand Down

0 comments on commit 21405b6

Please sign in to comment.