You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
Fixed a big audio bug, where varying timestamp values on low precision audio timebases (i.e. 1/1000) would leave small gaps in the audio wave. Also, fixed a few issues related to sample_rate getting lost between the reader and clip and timeline objects.
This commit is contained in:
@@ -86,9 +86,6 @@ namespace openshot {
|
||||
/// Adjust frame number minimum value
|
||||
int adjust_frame_number_minimum(int frame_number);
|
||||
|
||||
/// Apply basic image processing (scale, rotate, move, etc...)
|
||||
void apply_basic_image_processing(tr1::shared_ptr<Frame> frame, int frame_number);
|
||||
|
||||
/// Get file extension
|
||||
string get_file_extension(string path);
|
||||
|
||||
|
||||
@@ -69,12 +69,6 @@ namespace openshot
|
||||
bool check_interlace;
|
||||
bool check_fps;
|
||||
|
||||
// DEBUG STUFF
|
||||
int counter;
|
||||
int previous_audio_pts;
|
||||
int total_samples;
|
||||
audio_packet_location previous_packet_location;
|
||||
|
||||
int num_of_rescalers;
|
||||
int rescaler_position;
|
||||
vector<SwsContext*> image_rescalers;
|
||||
@@ -86,6 +80,7 @@ namespace openshot
|
||||
map<AVPicture*, AVPicture*> frames;
|
||||
map<int, int> processing_video_frames;
|
||||
map<int, int> processing_audio_frames;
|
||||
audio_packet_location previous_packet_location;
|
||||
|
||||
bool is_seeking;
|
||||
int seeking_pts;
|
||||
|
||||
16
src/Clip.cpp
16
src/Clip.cpp
@@ -191,9 +191,6 @@ tr1::shared_ptr<Frame> Clip::GetFrame(int requested_frame) throw(ReaderClosed)
|
||||
// Get time mapped frame number (used to increase speed, change direction, etc...)
|
||||
tr1::shared_ptr<Frame> new_frame = get_time_mapped_frame(frame, requested_frame);
|
||||
|
||||
// Apply basic image processing (scale, rotation, etc...)
|
||||
//apply_basic_image_processing(new_frame, new_frame_number);
|
||||
|
||||
// Return processed 'frame'
|
||||
return new_frame;
|
||||
}
|
||||
@@ -450,19 +447,6 @@ tr1::shared_ptr<Frame> Clip::get_time_mapped_frame(tr1::shared_ptr<Frame> frame,
|
||||
return new_frame;
|
||||
}
|
||||
|
||||
// Apply basic image processing (scale, rotate, move, etc...)
|
||||
void Clip::apply_basic_image_processing(tr1::shared_ptr<Frame> frame, int frame_number)
|
||||
{
|
||||
// Get values
|
||||
float rotation_value = rotation.GetValue(frame_number);
|
||||
//float scale_x_value = scale_x.GetValue(frame_number);
|
||||
//float scale_y_value = scale_y.GetValue(frame_number);
|
||||
|
||||
// rotate frame
|
||||
if (rotation_value != 0)
|
||||
frame->Rotate(rotation_value);
|
||||
}
|
||||
|
||||
// Adjust frame number minimum value
|
||||
int Clip::adjust_frame_number_minimum(int frame_number)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, Inval
|
||||
: last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0),
|
||||
audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false),
|
||||
check_fps(false), enable_seek(true), rescaler_position(0), num_of_rescalers(32), is_open(false),
|
||||
seek_audio_frame_found(-1), seek_video_frame_found(-1), resampleCtx(NULL), counter(0), previous_audio_pts(0), total_samples(0) {
|
||||
seek_audio_frame_found(-1), seek_video_frame_found(-1), resampleCtx(NULL) {
|
||||
|
||||
// Init FileInfo struct (clear all values)
|
||||
InitFileInfo();
|
||||
@@ -718,12 +718,6 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int
|
||||
// Allocate audio buffer
|
||||
int16_t *audio_buf = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
|
||||
|
||||
//if (packet->pts == 4378 || packet->pts == 4402)
|
||||
// cout << "ProcessAudioPacket: pts: " << packet->pts << ", my_packet->size: " << my_packet->size << endl;
|
||||
|
||||
// DEBUG COUNTER
|
||||
counter++;
|
||||
|
||||
int packet_samples = 0;
|
||||
while (my_packet->size > 0) {
|
||||
// re-initialize buffer size (it gets changed in the avcodec_decode_audio2 method call)
|
||||
@@ -745,7 +739,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int
|
||||
}
|
||||
|
||||
// Estimate the # of samples and the end of this packet's location (to prevent GAPS for the next timestamp)
|
||||
int pts_remaining_samples = packet_samples / info.channels;
|
||||
int pts_remaining_samples = round(packet_samples / info.channels);
|
||||
while (pts_remaining_samples)
|
||||
{
|
||||
// Get Samples per frame (for this frame number)
|
||||
@@ -770,18 +764,6 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int
|
||||
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
total_samples += packet_samples;
|
||||
cout << "packet: " << counter << ", PTS: " << packet->pts << ", PTS Diff: " << (packet->pts - previous_audio_pts) << ", samples: " << packet_samples << ", total: " << total_samples << endl;
|
||||
previous_audio_pts = packet->pts;
|
||||
// if (packet->pts >= 4378 && packet->pts <= 4500)
|
||||
// {
|
||||
// cout << "ProcessAudioPacket: pts: " << packet->pts << ", packet_samples: " << packet_samples << endl;
|
||||
// cout << "first samples for pts: " << packet->pts << ", " << audio_buf[0] << ", " << audio_buf[1] << ", " << audio_buf[2] << ", " << audio_buf[3] << ", " << audio_buf[4] << ", " << audio_buf[5] << endl;
|
||||
// cout << "last samples for pts: " << packet->pts << ", " << audio_buf[2045] << ", " << audio_buf[2046] << ", " << audio_buf[2047] << ", " << audio_buf[2048] << ", " << audio_buf[2049] << ", " << audio_buf[2050] << endl;
|
||||
// }
|
||||
|
||||
|
||||
#pragma omp critical (packet_cache)
|
||||
{
|
||||
// Remove packet
|
||||
@@ -789,8 +771,6 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int
|
||||
RemoveAVPacket(my_packet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma omp task firstprivate(requested_frame, target_frame, my_cache, starting_sample, audio_buf)
|
||||
{
|
||||
|
||||
@@ -835,7 +815,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int
|
||||
{
|
||||
// Array of floats (to hold samples for each channel)
|
||||
starting_frame_number = target_frame;
|
||||
int channel_buffer_size = (packet_samples / info.channels) + 1;
|
||||
int channel_buffer_size = round(packet_samples / info.channels);
|
||||
float *channel_buffer = new float[channel_buffer_size];
|
||||
|
||||
// Init buffer array
|
||||
@@ -1136,11 +1116,20 @@ audio_packet_location FFmpegReader::GetAudioPTSLocation(int pts)
|
||||
int diff_previous_packet = abs(location.sample_start - previous_packet_location.sample_start);
|
||||
if (location.frame == previous_packet_location.frame && diff_previous_packet >= 0 && diff_previous_packet <= 100)
|
||||
{
|
||||
if (location.frame >= 175 && location.frame < 220)
|
||||
cout << "GAP DETECTED!!! Changing frame " << location.frame << ", sample start: " << location.sample_start << " to " << previous_packet_location.sample_start + 1 << endl;
|
||||
int orig_frame = location.frame;
|
||||
int orig_start = location.sample_start;
|
||||
|
||||
// Update sample start, to prevent gaps in audio
|
||||
location.sample_start = previous_packet_location.sample_start + 1;
|
||||
if (previous_packet_location.sample_start + 1 <= samples_per_frame)
|
||||
location.sample_start = previous_packet_location.sample_start + 1;
|
||||
else
|
||||
{
|
||||
// set to next frame (since we exceeded the # of samples on a frame)
|
||||
location.sample_start = 0;
|
||||
location.frame++;
|
||||
}
|
||||
|
||||
//cout << "GAP DETECTED!!! Changing frame " << orig_frame << ":" << orig_start << " to frame " << location.frame << ":" << location.sample_start << endl;
|
||||
}
|
||||
|
||||
// Set previous location
|
||||
|
||||
@@ -526,9 +526,6 @@ void Frame::AddImage(tr1::shared_ptr<Magick::Image> new_image, float alpha)
|
||||
// Add audio samples to a specific channel
|
||||
void Frame::AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f)
|
||||
{
|
||||
if (number >= 181 && number < 220)
|
||||
cout << "AddAudio for frame: " << number << ", destChannel: " << destChannel << ", destStartSample: " << destStartSample << ", numSamples: " << numSamples << ", ending sample: " << (destStartSample + numSamples) << endl;
|
||||
|
||||
// Extend audio buffer (if needed)
|
||||
if (destStartSample + numSamples > audio->getNumSamples())
|
||||
audio->setSize(audio->getNumChannels(), destStartSample + numSamples, true, true, false);
|
||||
|
||||
@@ -26,6 +26,10 @@ FrameMapper::FrameMapper(FileReaderBase *reader, Framerate target, Pulldown_Meth
|
||||
info.video_timebase.num = target.GetFraction().den;
|
||||
info.video_timebase.den = target.GetFraction().num;
|
||||
info.video_length = round(info.duration * info.fps.ToDouble());
|
||||
info.sample_rate = reader->info.sample_rate;
|
||||
info.channels = reader->info.channels;
|
||||
info.width = reader->info.width;
|
||||
info.height = reader->info.height;
|
||||
|
||||
// Used to toggle odd / even fields
|
||||
field_toggle = true;
|
||||
@@ -252,6 +256,7 @@ tr1::shared_ptr<Frame> FrameMapper::GetFrame(int requested_frame) throw(ReaderCl
|
||||
|
||||
// Create a new frame
|
||||
tr1::shared_ptr<Frame> frame(new Frame(requested_frame, 1, 1, "#000000", samples_in_frame, info.channels));
|
||||
frame->SetSampleRate(info.sample_rate);
|
||||
|
||||
// Copy the image from the odd field (TODO: make this copy each field from the correct frames)
|
||||
frame->AddImage(reader->GetFrame(mapped.Odd.Frame)->GetImage(), true);
|
||||
|
||||
@@ -81,6 +81,7 @@ tr1::shared_ptr<Frame> ImageReader::GetFrame(int requested_frame) throw(ReaderCl
|
||||
{
|
||||
// Create or get frame object
|
||||
tr1::shared_ptr<Frame> image_frame(new Frame(requested_frame, image->size().width(), image->size().height(), "#000000", 0, 2));
|
||||
image_frame->SetSampleRate(44100);
|
||||
|
||||
// Add Image data to frame
|
||||
tr1::shared_ptr<Magick::Image> copy_image(new Magick::Image(*image.get()));
|
||||
|
||||
@@ -54,7 +54,7 @@ int main()
|
||||
|
||||
|
||||
// Create timeline
|
||||
Timeline t(620, 348, Framerate(24,1), 44100, 2);
|
||||
Timeline t(624, 348, Framerate(24,1), 44100, 2);
|
||||
|
||||
// Add some clips
|
||||
//Clip c1(new FFmpegReader("/home/jonathan/Apps/videcho_site/media/user_files/videos/bd0bf442-3221-11e2-8bf6-001fd00ee3aa.webm"));
|
||||
@@ -173,7 +173,7 @@ int main()
|
||||
// Set options
|
||||
//w.SetAudioOptions(true, "libmp3lame", 44100, 2, 128000, false);
|
||||
w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000, false);
|
||||
w.SetVideoOptions(true, "libvpx", Fraction(24, 1), 620, 348, Fraction(1,1), false, false, 2000000);
|
||||
w.SetVideoOptions(true, "libvpx", Fraction(24, 1), 624, 348, Fraction(1,1), false, false, 2000000);
|
||||
|
||||
// Prepare Streams
|
||||
w.PrepareStreams();
|
||||
@@ -184,7 +184,7 @@ int main()
|
||||
// Output stream info
|
||||
w.OutputStreamInfo();
|
||||
|
||||
for (int frame = 1; frame <= 300; frame++)
|
||||
for (int frame = 1; frame <= 600; frame++)
|
||||
{
|
||||
tr1::shared_ptr<Frame> f = t.GetFrame(frame);
|
||||
if (f)
|
||||
|
||||
@@ -14,6 +14,15 @@ Timeline::Timeline(int width, int height, Framerate fps, int sample_rate, int ch
|
||||
// Init cache
|
||||
int64 bytes = height * width * 4 + (44100 * 2 * 4);
|
||||
final_cache = Cache(20 * bytes); // 20 frames, 4 colors of chars, 2 audio channels of 4 byte floats
|
||||
|
||||
// Init FileInfo struct (clear all values)
|
||||
InitFileInfo();
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
info.fps = fps.GetFraction();
|
||||
info.sample_rate = sample_rate;
|
||||
info.channels = channels;
|
||||
info.video_timebase = fps.GetFraction().Reciprocal();
|
||||
}
|
||||
|
||||
// Add an openshot::Clip to the timeline
|
||||
@@ -49,7 +58,6 @@ void Timeline::add_layer(tr1::shared_ptr<Frame> new_frame, Clip* source_clip, in
|
||||
source_frame = tr1::shared_ptr<Frame>(source_clip->GetFrame(clip_frame_number));
|
||||
tr1::shared_ptr<Magick::Image> source_image = source_frame->GetImage();
|
||||
|
||||
|
||||
// Get some basic image properties
|
||||
int source_width = source_image->columns();
|
||||
int source_height = source_image->rows();
|
||||
@@ -273,6 +281,7 @@ tr1::shared_ptr<Frame> Timeline::GetFrame(int requested_frame) throw(ReaderClose
|
||||
{
|
||||
// Create blank frame (which will become the requested frame)
|
||||
tr1::shared_ptr<Frame> new_frame(tr1::shared_ptr<Frame>(new Frame(frame_number, width, height, "#000000", GetSamplesPerFrame(frame_number), channels)));
|
||||
new_frame->SetSampleRate(info.sample_rate);
|
||||
|
||||
// Calculate time of frame
|
||||
float requested_time = calculate_time(frame_number, fps);
|
||||
|
||||
Reference in New Issue
Block a user