Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Parborg <darkdefende@gmail.com>2021-07-06 20:48:06 +0300
committerSebastian Parborg <darkdefende@gmail.com>2021-08-16 16:10:58 +0300
commitded68fb10275c9f9a66e7019171b83cab0e9485d (patch)
tree8a7d8ad343433070b79f6bceec92871c564da1ec
parent6df81ddb84c60876ac3ebd87d1d134109f34eabd (diff)
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
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.cpp2
-rw-r--r--extern/audaspace/bindings/C/AUD_Types.h1
-rw-r--r--extern/audaspace/include/IReader.h6
-rw-r--r--extern/audaspace/include/fx/VolumeReader.h2
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp80
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.h17
-rw-r--r--extern/audaspace/src/fx/VolumeReader.cpp2
-rw-r--r--source/blender/blenkernel/BKE_sound.h9
-rw-r--r--source/blender/blenkernel/intern/sound.c12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c10
-rw-r--r--source/blender/imbuf/IMB_imbuf.h5
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h1
-rw-r--r--source/blender/imbuf/intern/anim_movie.c27
-rw-r--r--source/blender/makesdna/DNA_sound_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c5
-rw-r--r--source/blender/sequencer/SEQ_add.h6
-rw-r--r--source/blender/sequencer/intern/sound.c7
-rw-r--r--source/blender/sequencer/intern/strip_add.c46
-rw-r--r--source/blender/sequencer/intern/strip_time.c4
20 files changed, 197 insertions, 62 deletions
diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp
index ac876a01eb3..97e5f5540de 100644
--- a/extern/audaspace/bindings/C/AUD_Special.cpp
+++ b/extern/audaspace/bindings/C/AUD_Special.cpp
@@ -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&)
diff --git a/extern/audaspace/bindings/C/AUD_Types.h b/extern/audaspace/bindings/C/AUD_Types.h
index 75e4ffae18c..c6a96d30d3f 100644
--- a/extern/audaspace/bindings/C/AUD_Types.h
+++ b/extern/audaspace/bindings/C/AUD_Types.h
@@ -176,4 +176,5 @@ typedef struct
{
AUD_Specs specs;
float length;
+ double start_offset;
} AUD_SoundInfo;
diff --git a/extern/audaspace/include/IReader.h b/extern/audaspace/include/IReader.h
index c29900ca579..f6070b0f23b 100644
--- a/extern/audaspace/include/IReader.h
+++ b/extern/audaspace/include/IReader.h
@@ -71,6 +71,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.
*/
diff --git a/extern/audaspace/include/fx/VolumeReader.h b/extern/audaspace/include/fx/VolumeReader.h
index 13b6845e931..f7169f4c78b 100644
--- a/extern/audaspace/include/fx/VolumeReader.h
+++ b/extern/audaspace/include/fx/VolumeReader.h
@@ -67,4 +67,4 @@ public:
virtual void read(int& length, bool& eos, sample_t* buffer);
};
-AUD_NAMESPACE_END \ No newline at end of file
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
index b46f65eddbf..afdc7fcfcc6 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
@@ -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;
- 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;
+ if(m_st_time != AV_NOPTS_VALUE) {
+ seek_pts += m_st_time;
+ }
// 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);
}
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
index f62436ac83b..d613457c220 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
@@ -55,6 +55,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.
*/
DeviceSpecs m_specs;
@@ -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);
};
diff --git a/extern/audaspace/src/fx/VolumeReader.cpp b/extern/audaspace/src/fx/VolumeReader.cpp
index ac1d4882a87..627acbac9ef 100644
--- a/extern/audaspace/src/fx/VolumeReader.cpp
+++ b/extern/audaspace/src/fx/VolumeReader.cpp
@@ -57,4 +57,4 @@ void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
}
-AUD_NAMESPACE_END \ No newline at end of file
+AUD_NAMESPACE_END
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 57ce33a239f..4b257b3b8ab 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -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);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index fcb992e1535..9d287377545 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -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;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 47495eaa57a..ff8cbdb1a59 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -643,15 +643,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);
@@ -670,8 +672,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) {
@@ -679,7 +683,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);
@@ -822,7 +826,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);
}
@@ -840,7 +844,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;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 0472e1264ce..e49a88c88d2 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -284,10 +284,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(
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index d527aca184c..4ad7aa98484 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -367,6 +367,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!)
*/
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index cfeffcca0ea..c4e2ad9da7f 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -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 */
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index fd96110b59e..2998c4781b6 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -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;
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index b2bb50c56a2..e6394f0a56a 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -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;
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 4895ab11618..264ccccd350 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -310,7 +310,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);
@@ -359,7 +360,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");
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index 2941eb6f4c0..4025f1a4a04 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -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);
diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c
index 1054dbeeba6..c53aacddcfe 100644
--- a/source/blender/sequencer/intern/sound.c
+++ b/source/blender/sequencer/intern/sound.c
@@ -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 {
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index dab5593be37..cc70cc38ebb 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -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));
@@ -552,6 +583,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]);
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 68128690773..b73ac631693 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -34,6 +34,7 @@
#include "BKE_scene.h"
#include "BKE_sound.h"
+#include "DNA_sound_types.h"
#include "IMB_imbuf.h"
#include "SEQ_iterator.h"
@@ -134,7 +135,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);
}
}
}