Those are private fields, no reason to have them exposed in a public header.tags/n4.4
@@ -1122,35 +1122,6 @@ typedef struct AVStream { | |||||
*/ | */ | ||||
int skip_to_keyframe; | int skip_to_keyframe; | ||||
/** | |||||
* Number of samples to skip at the start of the frame decoded from the next packet. | |||||
*/ | |||||
int skip_samples; | |||||
/** | |||||
* If not 0, the number of samples that should be skipped from the start of | |||||
* the stream (the samples are removed from packets with pts==0, which also | |||||
* assumes negative timestamps do not happen). | |||||
* Intended for use with formats such as mp3 with ad-hoc gapless audio | |||||
* support. | |||||
*/ | |||||
int64_t start_skip_samples; | |||||
/** | |||||
* If not 0, the first audio sample that should be discarded from the stream. | |||||
* This is broken by design (needs global sample count), but can't be | |||||
* avoided for broken by design formats such as mp3 with ad-hoc gapless | |||||
* audio support. | |||||
*/ | |||||
int64_t first_discard_sample; | |||||
/** | |||||
* The sample after last sample that is intended to be discarded after | |||||
* first_discard_sample. Works on frame boundaries only. Used to prevent | |||||
* early EOF if the gapless info is broken (considered concatenated mp3s). | |||||
*/ | |||||
int64_t last_discard_sample; | |||||
/** | /** | ||||
* An opaque field for libavformat internal usage. | * An opaque field for libavformat internal usage. | ||||
* Must not be accessed in any way by callers. | * Must not be accessed in any way by callers. | ||||
@@ -225,6 +225,35 @@ struct AVStreamInternal { | |||||
} *info; | } *info; | ||||
/** | |||||
* Number of samples to skip at the start of the frame decoded from the next packet. | |||||
*/ | |||||
int skip_samples; | |||||
/** | |||||
* If not 0, the number of samples that should be skipped from the start of | |||||
* the stream (the samples are removed from packets with pts==0, which also | |||||
* assumes negative timestamps do not happen). | |||||
* Intended for use with formats such as mp3 with ad-hoc gapless audio | |||||
* support. | |||||
*/ | |||||
int64_t start_skip_samples; | |||||
/** | |||||
* If not 0, the first audio sample that should be discarded from the stream. | |||||
* This is broken by design (needs global sample count), but can't be | |||||
* avoided for broken by design formats such as mp3 with ad-hoc gapless | |||||
* audio support. | |||||
*/ | |||||
int64_t first_discard_sample; | |||||
/** | |||||
* The sample after last sample that is intended to be discarded after | |||||
* first_discard_sample. Works on frame boundaries only. Used to prevent | |||||
* early EOF if the gapless info is broken (considered concatenated mp3s). | |||||
*/ | |||||
int64_t last_discard_sample; | |||||
/** | /** | ||||
* Number of internally decoded frames, used internally in libavformat, do not access | * Number of internally decoded frames, used internally in libavformat, do not access | ||||
* its lifetime differs from info which is why it is not in that structure. | * its lifetime differs from info which is why it is not in that structure. | ||||
@@ -3550,7 +3550,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) | |||||
} | } | ||||
if (first_non_zero_audio_edit > 0) | if (first_non_zero_audio_edit > 0) | ||||
st->skip_samples = msc->start_pad = 0; | |||||
st->internal->skip_samples = msc->start_pad = 0; | |||||
} | } | ||||
// While reordering frame index according to edit list we must handle properly | // While reordering frame index according to edit list we must handle properly | ||||
@@ -3625,7 +3625,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) | |||||
curr_cts < edit_list_media_time && curr_cts + frame_duration > edit_list_media_time && | curr_cts < edit_list_media_time && curr_cts + frame_duration > edit_list_media_time && | ||||
first_non_zero_audio_edit > 0) { | first_non_zero_audio_edit > 0) { | ||||
packet_skip_samples = edit_list_media_time - curr_cts; | packet_skip_samples = edit_list_media_time - curr_cts; | ||||
st->skip_samples += packet_skip_samples; | |||||
st->internal->skip_samples += packet_skip_samples; | |||||
// Shift the index entry timestamp by packet_skip_samples to be correct. | // Shift the index entry timestamp by packet_skip_samples to be correct. | ||||
edit_list_dts_counter -= packet_skip_samples; | edit_list_dts_counter -= packet_skip_samples; | ||||
@@ -3658,7 +3658,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) | |||||
// Increment skip_samples for the first non-zero audio edit list | // Increment skip_samples for the first non-zero audio edit list | ||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && | if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && | ||||
first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { | first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { | ||||
st->skip_samples += frame_duration; | |||||
st->internal->skip_samples += frame_duration; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -3744,7 +3744,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) | |||||
// Update av stream length, if it ends up shorter than the track's media duration | // Update av stream length, if it ends up shorter than the track's media duration | ||||
st->duration = FFMIN(st->duration, edit_list_dts_entry_end - start_dts); | st->duration = FFMIN(st->duration, edit_list_dts_entry_end - start_dts); | ||||
msc->start_pad = st->skip_samples; | |||||
msc->start_pad = st->internal->skip_samples; | |||||
// Free the old index and the old CTTS structures | // Free the old index and the old CTTS structures | ||||
av_free(e_old); | av_free(e_old); | ||||
@@ -7616,7 +7616,7 @@ static int mov_read_header(AVFormatContext *s) | |||||
fix_timescale(mov, sc); | fix_timescale(mov, sc); | ||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && | if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && | ||||
st->codecpar->codec_id == AV_CODEC_ID_AAC) { | st->codecpar->codec_id == AV_CODEC_ID_AAC) { | ||||
st->skip_samples = sc->start_pad; | |||||
st->internal->skip_samples = sc->start_pad; | |||||
} | } | ||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0) | if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0) | ||||
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, | av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, | ||||
@@ -8105,7 +8105,7 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti | |||||
int64_t timestamp; | int64_t timestamp; | ||||
MOVStreamContext *sc = s->streams[i]->priv_data; | MOVStreamContext *sc = s->streams[i]->priv_data; | ||||
st = s->streams[i]; | st = s->streams[i]; | ||||
st->skip_samples = (sample_time <= 0) ? sc->start_pad : 0; | |||||
st->internal->skip_samples = (sample_time <= 0) ? sc->start_pad : 0; | |||||
if (stream_index == i) | if (stream_index == i) | ||||
continue; | continue; | ||||
@@ -255,13 +255,13 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st, | |||||
mp3->start_pad = v>>12; | mp3->start_pad = v>>12; | ||||
mp3-> end_pad = v&4095; | mp3-> end_pad = v&4095; | ||||
st->start_skip_samples = mp3->start_pad + 528 + 1; | |||||
st->internal->start_skip_samples = mp3->start_pad + 528 + 1; | |||||
if (mp3->frames) { | if (mp3->frames) { | ||||
st->first_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf; | |||||
st->last_discard_sample = mp3->frames * (int64_t)spf; | |||||
st->internal->first_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf; | |||||
st->internal->last_discard_sample = mp3->frames * (int64_t)spf; | |||||
} | } | ||||
if (!st->start_time) | if (!st->start_time) | ||||
st->start_time = av_rescale_q(st->start_skip_samples, | |||||
st->start_time = av_rescale_q(st->internal->start_skip_samples, | |||||
(AVRational){1, c->sample_rate}, | (AVRational){1, c->sample_rate}, | ||||
st->time_base); | st->time_base); | ||||
av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad); | av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad); | ||||
@@ -292,7 +292,7 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) | |||||
return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
ast->duration = avio_rl32(pb); // number of samples | ast->duration = avio_rl32(pb); // number of samples | ||||
if (((v>>4) & 15) == 2) { // MP3 sound data record | if (((v>>4) & 15) == 2) { // MP3 sound data record | ||||
ast->skip_samples = avio_rl16(pb); | |||||
ast->internal->skip_samples = avio_rl16(pb); | |||||
len -= 2; | len -= 2; | ||||
} | } | ||||
len -= 7; | len -= 7; | ||||
@@ -1123,7 +1123,7 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, | |||||
if (st->start_time == AV_NOPTS_VALUE && pktl_it->pkt.pts != AV_NOPTS_VALUE) { | if (st->start_time == AV_NOPTS_VALUE && pktl_it->pkt.pts != AV_NOPTS_VALUE) { | ||||
st->start_time = pktl_it->pkt.pts; | st->start_time = pktl_it->pkt.pts; | ||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate) | if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate) | ||||
st->start_time = av_sat_add64(st->start_time, av_rescale_q(st->skip_samples, (AVRational){1, st->codecpar->sample_rate}, st->time_base)); | |||||
st->start_time = av_sat_add64(st->start_time, av_rescale_q(st->internal->skip_samples, (AVRational){1, st->codecpar->sample_rate}, st->time_base)); | |||||
} | } | ||||
} | } | ||||
@@ -1136,7 +1136,7 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, | |||||
st->start_time = pts; | st->start_time = pts; | ||||
} | } | ||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate) | if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate) | ||||
st->start_time = av_sat_add64(st->start_time, av_rescale_q(st->skip_samples, (AVRational){1, st->codecpar->sample_rate}, st->time_base)); | |||||
st->start_time = av_sat_add64(st->start_time, av_rescale_q(st->internal->skip_samples, (AVRational){1, st->codecpar->sample_rate}, st->time_base)); | |||||
} | } | ||||
} | } | ||||
@@ -1639,25 +1639,25 @@ FF_ENABLE_DEPRECATION_WARNINGS | |||||
if (ret >= 0) { | if (ret >= 0) { | ||||
AVStream *st = s->streams[pkt->stream_index]; | AVStream *st = s->streams[pkt->stream_index]; | ||||
int discard_padding = 0; | int discard_padding = 0; | ||||
if (st->first_discard_sample && pkt->pts != AV_NOPTS_VALUE) { | |||||
if (st->internal->first_discard_sample && pkt->pts != AV_NOPTS_VALUE) { | |||||
int64_t pts = pkt->pts - (is_relative(pkt->pts) ? RELATIVE_TS_BASE : 0); | int64_t pts = pkt->pts - (is_relative(pkt->pts) ? RELATIVE_TS_BASE : 0); | ||||
int64_t sample = ts_to_samples(st, pts); | int64_t sample = ts_to_samples(st, pts); | ||||
int duration = ts_to_samples(st, pkt->duration); | int duration = ts_to_samples(st, pkt->duration); | ||||
int64_t end_sample = sample + duration; | int64_t end_sample = sample + duration; | ||||
if (duration > 0 && end_sample >= st->first_discard_sample && | |||||
sample < st->last_discard_sample) | |||||
discard_padding = FFMIN(end_sample - st->first_discard_sample, duration); | |||||
if (duration > 0 && end_sample >= st->internal->first_discard_sample && | |||||
sample < st->internal->last_discard_sample) | |||||
discard_padding = FFMIN(end_sample - st->internal->first_discard_sample, duration); | |||||
} | } | ||||
if (st->start_skip_samples && (pkt->pts == 0 || pkt->pts == RELATIVE_TS_BASE)) | |||||
st->skip_samples = st->start_skip_samples; | |||||
if (st->skip_samples || discard_padding) { | |||||
if (st->internal->start_skip_samples && (pkt->pts == 0 || pkt->pts == RELATIVE_TS_BASE)) | |||||
st->internal->skip_samples = st->internal->start_skip_samples; | |||||
if (st->internal->skip_samples || discard_padding) { | |||||
uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); | uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); | ||||
if (p) { | if (p) { | ||||
AV_WL32(p, st->skip_samples); | |||||
AV_WL32(p, st->internal->skip_samples); | |||||
AV_WL32(p + 4, discard_padding); | AV_WL32(p + 4, discard_padding); | ||||
av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d / discard %d\n", st->skip_samples, discard_padding); | |||||
av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d / discard %d\n", st->internal->skip_samples, discard_padding); | |||||
} | } | ||||
st->skip_samples = 0; | |||||
st->internal->skip_samples = 0; | |||||
} | } | ||||
if (st->internal->inject_global_side_data) { | if (st->internal->inject_global_side_data) { | ||||
@@ -1891,7 +1891,7 @@ void ff_read_frame_flush(AVFormatContext *s) | |||||
if (s->internal->inject_global_side_data) | if (s->internal->inject_global_side_data) | ||||
st->internal->inject_global_side_data = 1; | st->internal->inject_global_side_data = 1; | ||||
st->skip_samples = 0; | |||||
st->internal->skip_samples = 0; | |||||
} | } | ||||
} | } | ||||