VSE: Fix audaspace not reading ffmpeg files with start offset correctly

The duration and start time for audio strips were not correctly read in
audaspace.

Some video files have a "lead in" section of audio that plays before the
video starts playing back. Before this patch, we would play this lead in
audio at the same time as the video started and thus the audio would not
be in sync anymore.

Now the lead in audio is cut off and the duration should be correctly
calculated with this in mind.

If the audio starts after the video, the audio strip is shifted to
account for this, but it will also lead to cut off audio which might not
be wanted. However we don't have a simple way to solve this at this
point.

Differential Revision: http://developer.blender.org/D11917
This commit is contained in:
Sebastian Parborg 2021-07-06 19:48:06 +02:00 committed by Jeroen Bakker
parent 00dd68405d
commit 489df7ac88
Notes: blender-bot 2023-02-14 10:35:28 +01:00
Referenced by issue #88449, Blender LTS: Maintenance Task 2.93
20 changed files with 197 additions and 62 deletions

View File

@ -86,6 +86,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
info.specs.channels = AUD_CHANNELS_INVALID;
info.specs.rate = AUD_RATE_INVALID;
info.length = 0.0f;
info.start_offset = 0.0f;
try
{
@ -95,6 +96,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
{
info.specs = convSpecToC(reader->getSpecs());
info.length = reader->getLength() / (float) info.specs.rate;
info.start_offset = reader->getStartOffset();
}
}
catch(Exception&)

View File

@ -176,4 +176,5 @@ typedef struct
{
AUD_Specs specs;
float length;
double start_offset;
} AUD_SoundInfo;

View File

@ -70,6 +70,12 @@ public:
*/
virtual int getPosition() const=0;
/**
* Returns the start offset the sound should have to line up with related sources.
* \return The required start offset in seconds.
*/
virtual double getStartOffset() const { return 0.0;}
/**
* Returns the specification of the reader.
* \return The Specs structure.

View File

@ -67,4 +67,4 @@ public:
virtual void read(int& length, bool& eos, sample_t* buffer);
};
AUD_NAMESPACE_END
AUD_NAMESPACE_END

View File

@ -68,7 +68,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
m_frame->data[channel] + i * single_size, single_size);
m_frame->data[channel] + i * single_size, single_size);
}
}
}
@ -109,7 +109,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
m_frame->data[channel] + i * single_size, single_size);
m_frame->data[channel] + i * single_size, single_size);
}
}
}
@ -126,7 +126,10 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
void FFMPEGReader::init()
{
m_position = 0;
m_start_offset = 0.0f;
m_pkgbuf_left = 0;
m_st_time = 0;
m_duration = 0;
if(avformat_find_stream_info(m_formatCtx, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg couldn't find the stream info.");
@ -134,15 +137,41 @@ void FFMPEGReader::init()
// find audio stream and codec
m_stream = -1;
double dur_sec = 0;
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{
#ifdef FFMPEG_OLD_CODE
if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
#endif
&& (m_stream < 0))
{
AVStream *audio_stream = m_formatCtx->streams[i];
double audio_timebase = av_q2d(audio_stream->time_base);
if (audio_stream->start_time != AV_NOPTS_VALUE)
{
m_st_time = audio_stream->start_time;
}
int64_t ctx_start_time = 0;
if (m_formatCtx->start_time != AV_NOPTS_VALUE) {
ctx_start_time = m_formatCtx->start_time;
}
m_start_offset = m_st_time * audio_timebase - (double)ctx_start_time / AV_TIME_BASE;
if(audio_stream->duration != AV_NOPTS_VALUE)
{
dur_sec = audio_stream->duration * audio_timebase;
}
else
{
/* If the audio starts after the stream start time, subract this from the total duration. */
dur_sec = (double)m_formatCtx->duration / AV_TIME_BASE - m_start_offset;
}
m_stream=i;
break;
}
@ -213,6 +242,7 @@ void FFMPEGReader::init()
}
m_specs.rate = (SampleRate) m_codecCtx->sample_rate;
m_duration = lround(dur_sec * m_codecCtx->sample_rate);
}
FFMPEGReader::FFMPEGReader(std::string filename) :
@ -338,21 +368,17 @@ void FFMPEGReader::seek(int position)
{
if(position >= 0)
{
uint64_t st_time = m_formatCtx->start_time;
uint64_t seek_pos = ((uint64_t)position) * ((uint64_t)AV_TIME_BASE) / ((uint64_t)m_specs.rate);
double pts_time_base =
av_q2d(m_formatCtx->streams[m_stream]->time_base);
if(st_time != AV_NOPTS_VALUE) {
seek_pos += st_time;
uint64_t seek_pts = (((uint64_t)position) / ((uint64_t)m_specs.rate)) / pts_time_base;
if(m_st_time != AV_NOPTS_VALUE) {
seek_pts += m_st_time;
}
double pts_time_base =
av_q2d(m_formatCtx->streams[m_stream]->time_base);
uint64_t pts_st_time =
((st_time != AV_NOPTS_VALUE) ? st_time : 0)
/ pts_time_base / (uint64_t) AV_TIME_BASE;
// a value < 0 tells us that seeking failed
if(av_seek_frame(m_formatCtx, -1, seek_pos,
if(av_seek_frame(m_formatCtx, m_stream, seek_pts,
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
{
avcodec_flush_buffers(m_codecCtx);
@ -374,7 +400,7 @@ void FFMPEGReader::seek(int position)
if(packet.pts != AV_NOPTS_VALUE)
{
// calculate real position, and read to frame!
m_position = (packet.pts - pts_st_time) * pts_time_base * m_specs.rate;
m_position = (packet.pts - m_st_time) * pts_time_base * m_specs.rate;
if(m_position < position)
{
@ -405,8 +431,7 @@ void FFMPEGReader::seek(int position)
int FFMPEGReader::getLength() const
{
// return approximated remaning size
return (int)((m_formatCtx->duration * m_codecCtx->sample_rate)
/ AV_TIME_BASE)-m_position;
return m_duration - m_position;
}
int FFMPEGReader::getPosition() const
@ -414,6 +439,11 @@ int FFMPEGReader::getPosition() const
return m_position;
}
double FFMPEGReader::getStartOffset() const
{
return m_start_offset;
}
Specs FFMPEGReader::getSpecs() const
{
return m_specs.specs;
@ -450,11 +480,13 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
// decode the package
pkgbuf_pos = decode(packet, m_pkgbuf);
// copy to output buffer
data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size / sample_size;
if (packet.pts >= m_st_time) {
// copy to output buffer
data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size / sample_size;
}
}
av_packet_unref(&packet);
}

View File

@ -54,6 +54,22 @@ private:
*/
int m_position;
/**
* The start offset in seconds relative to the media container start time.
* IE how much the sound should be delayed to be kept in sync with the rest of the containter streams.
*/
double m_start_offset;
/**
* The start time pts of the stream. All packets before this timestamp shouldn't be played back (only decoded).
*/
int64_t m_st_time;
/**
* The duration of the audio stream in samples.
*/
int64_t m_duration;
/**
* The specification of the audio data.
*/
@ -182,6 +198,7 @@ public:
virtual void seek(int position);
virtual int getLength() const;
virtual int getPosition() const;
virtual double getStartOffset() const;
virtual Specs getSpecs() const;
virtual void read(int& length, bool& eos, sample_t* buffer);
};

View File

@ -57,4 +57,4 @@ void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
}
AUD_NAMESPACE_END
AUD_NAMESPACE_END

View File

@ -97,6 +97,7 @@ typedef struct SoundInfo {
eSoundChannels channels;
} specs;
float length;
double start_offset;
} SoundInfo;
/* Get information about given sound. Returns truth on success., false if sound can not be loaded
@ -139,8 +140,12 @@ void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle);
void BKE_sound_mute_scene_sound(void *handle, char mute);
void BKE_sound_move_scene_sound(
struct Scene *scene, void *handle, int startframe, int endframe, int frameskip);
void BKE_sound_move_scene_sound(struct Scene *scene,
void *handle,
int startframe,
int endframe,
int frameskip,
double audio_offset);
void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
void BKE_sound_update_scene_sound(void *handle, struct bSound *sound);

View File

@ -709,7 +709,7 @@ void *BKE_sound_scene_add_scene_sound(
sequence->scene->sound_scene,
startframe / fps,
endframe / fps,
frameskip / fps);
frameskip / fps + sequence->sound->offset_time);
}
return NULL;
}
@ -737,7 +737,7 @@ void *BKE_sound_add_scene_sound(
sequence->sound->playback_handle,
startframe / fps,
endframe / fps,
frameskip / fps);
frameskip / fps + sequence->sound->offset_time);
AUD_SequenceEntry_setMuted(handle, (sequence->flag & SEQ_MUTE) != 0);
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, CFRA, &sequence->volume, 0);
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, CFRA, &sequence->pitch, 0);
@ -765,11 +765,11 @@ void BKE_sound_mute_scene_sound(void *handle, char mute)
}
void BKE_sound_move_scene_sound(
Scene *scene, void *handle, int startframe, int endframe, int frameskip)
Scene *scene, void *handle, int startframe, int endframe, int frameskip, double audio_offset)
{
sound_verify_evaluated_id(&scene->id);
const double fps = FPS;
AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps);
AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps + audio_offset);
}
void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence)
@ -780,7 +780,8 @@ void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence)
sequence->scene_sound,
sequence->startdisp,
sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
sequence->startofs + sequence->anim_startofs,
sequence->sound->offset_time);
}
}
@ -1213,6 +1214,7 @@ static bool sound_info_from_playback_handle(void *playback_handle, SoundInfo *so
AUD_SoundInfo info = AUD_getInfo(playback_handle);
sound_info->specs.channels = (eSoundChannels)info.specs.channels;
sound_info->length = info.length;
sound_info->start_offset = info.start_offset;
return true;
}

View File

@ -646,15 +646,17 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
double video_start_offset;
load_data->channel++;
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data);
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data, &video_start_offset);
load_data->channel--;
if (seq_movie == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
}
else {
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, video_start_offset);
}
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
seq_load_apply_generic_options(C, op, seq_sound);
@ -673,8 +675,10 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
double video_start_offset;
load_data->channel++;
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data);
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data, &video_start_offset);
load_data->channel--;
if (seq_movie == NULL) {
@ -682,7 +686,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
return false;
}
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, video_start_offset);
}
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
@ -827,7 +831,7 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only);
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, 0.0f);
if (seq == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
}
@ -845,7 +849,7 @@ static bool sequencer_add_sound_single_strip(bContext *C, wmOperator *op, SeqLoa
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, true);
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, 0.0f);
if (seq == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
return false;

View File

@ -288,10 +288,12 @@ static void draw_seq_waveform_overlay(View2D *v2d,
return;
}
startsample = floor((seq->startofs + seq->anim_startofs) / FPS *
SOUND_WAVE_SAMPLES_PER_SECOND);
endsample = ceil((seq->startofs + seq->anim_startofs + seq->enddisp - seq->startdisp) / FPS *
SOUND_WAVE_SAMPLES_PER_SECOND);
startsample = (seq->startofs + seq->anim_startofs) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND;
startsample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
endsample = (seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND;
endsample += startsample;
samplestep = (endsample - startsample) * stepsize / (x2 - x1);
length = min_ii(

View File

@ -355,6 +355,11 @@ void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop
*/
int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc);
/**
* Return the encoded start offset (in seconds) of the given \a anim.
*/
double IMD_anim_get_offset(struct anim *anim);
/**
* Return the fps contained in movie files (function rval is false,
* and frs_sec and frs_sec_base untouched if none available!)

View File

@ -91,6 +91,7 @@ struct anim {
int duration_in_frames;
int frs_sec;
double frs_sec_base;
double start_offset;
int x, y;
/* for number */

View File

@ -425,6 +425,7 @@ static int startavi(struct anim *anim)
}
anim->duration_in_frames = anim->avi->header->TotalFrames;
anim->start_offset = 0.0f;
anim->params = NULL;
anim->x = anim->avi->header->Width;
@ -597,6 +598,13 @@ static int startffmpeg(struct anim *anim)
return -1;
}
double video_start = 0;
double pts_time_base = av_q2d(video_stream->time_base);
if (video_stream->start_time != AV_NOPTS_VALUE) {
video_start = video_stream->start_time * pts_time_base;
}
frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL);
anim->duration_in_frames = 0;
@ -620,20 +628,14 @@ static int startffmpeg(struct anim *anim)
* This is because the video stream duration can be shorter than the pFormatCtx->duration.
*/
if (anim->duration_in_frames == 0) {
double pts_time_base = av_q2d(video_stream->time_base);
double stream_dur;
if (video_stream->duration != AV_NOPTS_VALUE) {
stream_dur = video_stream->duration * pts_time_base;
}
else {
double video_start = 0;
double audio_start = 0;
if (video_stream->start_time != AV_NOPTS_VALUE) {
video_start = video_stream->start_time * pts_time_base;
}
/* Find audio stream to guess the duration of the video.
* Sometimes the audio AND the video stream have a start offset.
* The difference between these is the offset we want to use to
@ -662,6 +664,11 @@ static int startffmpeg(struct anim *anim)
anim->duration_in_frames = (int)(stream_dur * av_q2d(frame_rate) + 0.5f);
}
double ctx_start = 0;
if (pFormatCtx->start_time != AV_NOPTS_VALUE) {
ctx_start = (double)pFormatCtx->start_time / AV_TIME_BASE;
}
frs_num = frame_rate.num;
frs_den = frame_rate.den;
@ -674,6 +681,9 @@ static int startffmpeg(struct anim *anim)
anim->frs_sec = frs_num;
anim->frs_sec_base = frs_den;
/* Save the relative start time for the video. IE the start time in relation to where playback
* starts. */
anim->start_offset = video_start - ctx_start;
anim->params = 0;
@ -1672,6 +1682,11 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
return IMB_indexer_get_duration(idx);
}
double IMD_anim_get_offset(struct anim *anim)
{
return anim->start_offset;
}
bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base)
{
double frs_sec_base_double;

View File

@ -67,6 +67,7 @@ typedef struct bSound {
/** Runtime only, always reset in readfile. */
short tags;
char _pad[4];
double offset_time;
/* Unused currently. */
// int type;

View File

@ -290,7 +290,8 @@ static Sequence *rna_Sequences_new_movie(ID *id,
SEQ_add_load_data_init(&load_data, name, file, frame_start, channel);
load_data.fit_method = fit_method;
load_data.allow_invalid_file = true;
Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data);
double video_start_offset;
Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data, &video_start_offset);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -339,7 +340,7 @@ static Sequence *rna_Sequences_new_sound(ID *id,
SeqLoadData load_data;
SEQ_add_load_data_init(&load_data, name, file, frame_start, channel);
load_data.allow_invalid_file = true;
Sequence *seq = SEQ_add_sound_strip(bmain, scene, seqbase, &load_data);
Sequence *seq = SEQ_add_sound_strip(bmain, scene, seqbase, &load_data, 0.0f);
if (seq == NULL) {
BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file");

View File

@ -79,14 +79,16 @@ struct Sequence *SEQ_add_image_strip(struct Main *bmain,
struct Sequence *SEQ_add_sound_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct SeqLoadData *load_data,
const double audio_offset);
struct Sequence *SEQ_add_meta_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct Sequence *SEQ_add_movie_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
struct SeqLoadData *load_data,
double *r_video_start_offset);
struct Sequence *SEQ_add_scene_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);

View File

@ -111,7 +111,12 @@ void SEQ_sound_update_bounds(Scene *scene, Sequence *seq)
/* We have to take into account start frame of the sequence's scene! */
int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
BKE_sound_move_scene_sound(scene,
seq->scene_sound,
seq->startdisp,
seq->enddisp,
startofs,
seq->sound->offset_time);
}
}
else {

View File

@ -382,9 +382,14 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
* \return created strip
*/
Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
Sequence *SEQ_add_sound_strip(Main *bmain,
Scene *scene,
ListBase *seqbase,
SeqLoadData *load_data,
const double audio_offset)
{
bSound *sound = BKE_sound_new_file(bmain, load_data->path); /* Handles relative paths. */
sound->offset_time = audio_offset;
SoundInfo info;
bool sound_loaded = BKE_sound_info_get(bmain, sound, &info);
@ -398,14 +403,36 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
return NULL;
}
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SOUND_RAM);
/* If this sound it part of a video, then the sound might start after the video.
* In this case we need to then offset the start frame of the audio so it syncs up
* properly with the video.
*/
int start_frame_offset = info.start_offset * FPS;
double start_frame_offset_remainer = (info.start_offset * FPS - start_frame_offset) / FPS;
if (start_frame_offset_remainer > FLT_EPSILON) {
/* We can't represent a fraction of a frame, so skip the first frame fraction of sound so we
* start on a "whole" frame.
*/
start_frame_offset++;
}
sound->offset_time += start_frame_offset_remainer;
Sequence *seq = SEQ_sequence_alloc(seqbase,
load_data->start_frame + start_frame_offset,
load_data->channel,
SEQ_TYPE_SOUND_RAM);
seq->sound = sound;
seq->scene_sound = NULL;
/* We add a very small negative offset here, because
* ceil(132.0) == 133.0, not nice with videos, see T47135. */
seq->len = MAX2(1, (int)ceil((double)info.length * FPS - 1e-4));
/* We round the frame duration as the audio sample lenghts usually does not
* line up with the video frames. Therefore we round this number to the
* nearsest frame as the audio track usually overshoots or undershoots the
* end frame ofthe video by a little bit.
* See T47135 for under shoot example.
*/
seq->len = MAX2(1, round((info.length - sound->offset_time) * FPS));
Strip *strip = seq->strip;
/* We only need 1 element to store the filename. */
@ -477,7 +504,11 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_
* \param load_data: SeqLoadData with information necessary to create strip
* \return created strip
*/
Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
Sequence *SEQ_add_movie_strip(Main *bmain,
Scene *scene,
ListBase *seqbase,
SeqLoadData *load_data,
double *r_video_start_offset)
{
char path[sizeof(load_data->path)];
BLI_strncpy(path, load_data->path, sizeof(path));
@ -550,6 +581,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
if (anim_arr[0] != NULL) {
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
*r_video_start_offset = IMD_anim_get_offset(anim_arr[0]);
IMB_anim_load_metadata(anim_arr[0]);

View File

@ -34,6 +34,7 @@
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "DNA_sound_types.h"
#include "IMB_imbuf.h"
#include "SEQ_render.h"
@ -133,7 +134,8 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene,
seq->scene_sound,
seq->start + startofs,
seq->start + seq->len - endofs,
startofs + seq->anim_startofs);
startofs + seq->anim_startofs,
seq->sound->offset_time);
}
}
}