diff --git a/include/Frame.h b/include/Frame.h index 44550be1..9add1357 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -80,8 +80,8 @@ namespace openshot /// Get an array of sample data float* GetAudioSamples(int channel); - /// Get an array of sample data (all channels interleaved together) - float* GetAudioSamples(); + /// Get an array of sample data (all channels interleaved together), using any sample rate + float* GetInterleavedAudioSamples(int new_sample_rate, int* sample_count); /// Get number of audio channels int GetAudioChannelsCount(); diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 161fec18..02e5f028 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -757,6 +757,17 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // Add or update cache my_cache->Add(f.number, f); + + // DEBUG +// for (int s = start; s 500) +// { +// cout << iterate_channel_buffer[s] << endl; +// } +// else if (f.number == 2 && s < 34) +// { +// cout << iterate_channel_buffer[s] << endl; +// } } // Decrement remaining samples diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 93d8e408..97239498 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -314,8 +314,8 @@ AVStream* FFmpegWriter::add_audio_stream() // Check for valid timebase if (c->time_base.den == 0 || c->time_base.num == 0) { - c->time_base.num = 1; - c->time_base.den = 90000; + c->time_base.num = st->time_base.num; + c->time_base.den = st->time_base.den; } // Set valid sample rate (or throw error) @@ -334,6 +334,7 @@ AVStream* FFmpegWriter::add_audio_stream() // Set sample rate c->sample_rate = info.sample_rate; + // Set a valid number of channels (or throw error) int channel_layout = info.channels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; if (codec->channel_layouts) { @@ -351,6 +352,7 @@ AVStream* FFmpegWriter::add_audio_stream() // Set valid channel layout c->channel_layout = channel_layout; + // Choose a valid sample_fmt if (codec->sample_fmts) { for (int i = 0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) @@ -504,22 +506,31 @@ void FFmpegWriter::write_audio_packet(Frame* frame) c = audio_st->codec; // Get the audio details from this frame - int sample_rate_in_frame = frame->GetAudioSamplesRate(); - int samples_in_frame = frame->GetAudioSamplesCount(); + int sample_rate_in_frame = info.sample_rate; // resampling happens when getting the interleaved audio samples below + int samples_in_frame = frame->GetAudioSamplesCount(); // this is updated if resampling happens int channels_in_frame = frame->GetAudioChannelsCount(); - int total_frame_samples = samples_in_frame * channels_in_frame; - int remaining_frame_samples = total_frame_samples; // Get audio sample array - float* frame_samples_float = frame->GetAudioSamples(); + float* frame_samples_float = frame->GetInterleavedAudioSamples(info.sample_rate, &samples_in_frame); int16_t* frame_samples = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; int samples_position = 0; + // Calculate total samples + int total_frame_samples = samples_in_frame * channels_in_frame; + int remaining_frame_samples = total_frame_samples; + // Translate audio sample values back to 16 bit integers for (int s = 0; s < total_frame_samples; s++) { // Translate sample value and copy into buffer frame_samples[s] = int(frame_samples_float[s] * (1 << 15)); + +// // DEBUG +// if (frame->number == 1) +// { +// cout << frame_samples[s] << endl; +// } + } // Re-sample audio samples (if needed) @@ -530,7 +541,7 @@ void FFmpegWriter::write_audio_packet(Frame* frame) ReSampleContext *resampleCtx = av_audio_resample_init( info.channels, channels_in_frame, info.sample_rate, sample_rate_in_frame, - c->sample_fmt, AV_SAMPLE_FMT_S16, 0, 0, 0, 0.0f); + c->sample_fmt, AV_SAMPLE_FMT_S16, 16, 10, 0, 0.0f); if (!resampleCtx) throw InvalidCodec("Failed to convert audio samples for encoding.", path); @@ -539,6 +550,14 @@ void FFmpegWriter::write_audio_packet(Frame* frame) total_frame_samples = audio_resample(resampleCtx, (short *) converted_audio, (short *) frame_samples, total_frame_samples); remaining_frame_samples = total_frame_samples; + // DEBUG +// cout << endl << endl << endl << "END OF RESAMPLE DATA:" << endl; +// if (frame->number == 1) +// { +// for (int s = total_frame_samples - 10; s < (total_frame_samples + 200); s++) +// cout << converted_audio[s] << endl; +// } + // Copy audio samples over original samples memcpy(frame_samples, converted_audio, total_frame_samples * av_get_bytes_per_sample(c->sample_fmt)); @@ -547,6 +566,14 @@ void FFmpegWriter::write_audio_packet(Frame* frame) } } +// // DEBUG +// cout << endl << endl << endl << "AFTER RESCALE" << endl; +// if (frame->number == 1) +// { +// for (int s = 0; s < total_frame_samples; s++) +// cout << frame_samples[s] << endl; +// } + // Loop until no more samples while (remaining_frame_samples > 0) { // Get remaining samples needed for this packet @@ -567,7 +594,7 @@ void FFmpegWriter::write_audio_packet(Frame* frame) // Copy samples into input buffer (and convert to 16 bit int) - for (int s = 0; s <= diff; s++) + for (int s = 0; s < diff; s++) { // Translate sample value and copy into buffer samples[audio_input_position] = frame_samples[samples_position]; @@ -577,20 +604,32 @@ void FFmpegWriter::write_audio_packet(Frame* frame) samples_position++; remaining_frame_samples--; remaining_packet_samples--; + + // DEBUG +// if (frame->number == 1 && s > 2800) +// { +// cout << frame_samples[s] << endl; +// } +// if (frame->number == 2 && s < 100) +// { +// cout << frame_samples[s] << endl; +// } } +// if (frame->number == 2 || frame->number == 3) +// { +// for (int z = 0; z < diff; z++) +// cout << frame_samples[z] << endl; +// } + + // Do we have enough samples to proceed? if (audio_input_position < audio_input_frame_size) // Not enough samples to encode... so wait until the next frame break; cout << "NOW ENCODE FILE!" << endl; -// if (frame->number == 5) -// { -// for (int z = 0; z < audio_input_frame_size; z++) -// cout << samples[z] << endl; -// } // Set packet properties pkt.size = avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, (short *) samples); @@ -601,6 +640,8 @@ void FFmpegWriter::write_audio_packet(Frame* frame) pkt.stream_index = audio_st->index; pkt.data = audio_outbuf; + cout << "Final encode: frame " << frame->number << ", pkt.pts: " << pkt.pts << endl; + /* write the compressed frame in the media file */ if (av_interleaved_write_frame(oc, &pkt) != 0) throw ErrorEncodingAudio("Error while writing audio frame", frame->number); diff --git a/src/Frame.cpp b/src/Frame.cpp index 71e54e0c..70e6f28e 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -250,25 +250,113 @@ float* Frame::GetAudioSamples(int channel) return audio->getSampleData(channel); } -// Get an array of sample data (all channels interleaved together) -float* Frame::GetAudioSamples() +// Get an array of sample data (all channels interleaved together), using any sample rate +float* Frame::GetInterleavedAudioSamples(int new_sample_rate, int* sample_count) { - float *output = new float[audio->getNumChannels() * audio->getNumSamples()]; + float *output = NULL; + AudioSampleBuffer *buffer = audio; + int num_of_channels = audio->getNumChannels(); + int num_of_samples = audio->getNumSamples(); + + + // DEBUG + cout << "output size 1: " << (num_of_channels * num_of_samples) << endl; + cout << "buffer channels 1: " << buffer->getNumChannels() << endl; + cout << "buffer samples 1: " << buffer->getNumSamples() << endl; + cout << "--------------" << endl; + +// // Loop through samples in each channel (combining them) +// if (number == 1) +// { +// cout << "BEFORE RESAMPLE" << endl << endl; +// for (int sample = 0; sample < num_of_samples; sample++) +// { +// for (int channel = 0; channel < num_of_channels; channel++) +// { +// // Add sample to output array +// cout << buffer->getSampleData(channel)[sample] << endl; +// } +// } +// } + + + // Resample to new sample rate (if needed) + if (new_sample_rate != sample_rate) + { + // YES, RESAMPLE AUDIO + + // Get the frame's audio source + AudioBufferSource my_source(num_of_samples, num_of_channels); + + // Add audio to AudioBufferSource + for (int channel = 0; channel < num_of_channels; channel++) + { + // Add audio for each channel + my_source.AddAudio(channel, 0, audio->getSampleData(channel), num_of_samples, 1.0f); + } + + // Create resample source + ResamplingAudioSource resample_source(&my_source, false, num_of_channels); + + // Set the sample ratio (original to new sample rate) + double source_ratio = double(sample_rate) / double(new_sample_rate); + double dest_ratio = double(new_sample_rate) / double(sample_rate); + int new_num_of_samples = num_of_samples * dest_ratio; + resample_source.setResamplingRatio(dest_ratio); + + // Prepare to resample + resample_source.prepareToPlay(num_of_samples, new_sample_rate); + + // Create a buffer for the newly resampled data + AudioSampleBuffer resampled_buffer(num_of_channels, new_num_of_samples); + resampled_buffer.clear(); + const AudioSourceChannelInfo resample_callback_buffer = {&resampled_buffer, 0, new_num_of_samples}; + resample_callback_buffer.clearActiveBufferRegion(); + + // Resample the current frame's audio buffer (info the temp callback buffer) + resample_source.getNextAudioBlock(resample_callback_buffer); + + // Update buffer pointer to this newly resampled buffer + buffer = &resampled_buffer; + + // Update num_of_samples + num_of_samples = new_num_of_samples; + + } + + + // DEBUG + cout << "output size 2: " << (num_of_channels * num_of_samples) << endl; + cout << "buffer channels 2: " << buffer->getNumChannels() << endl; + cout << "buffer samples 2: " << buffer->getNumSamples() << endl; + + + // INTERLEAVE all samples together (channel 1 + channel 2 + channel 1 + channel 2, etc...) + output = new float[num_of_channels * num_of_samples]; int position = 0; // Loop through samples in each channel (combining them) - for (int sample = 0; sample < audio->getNumSamples(); sample++) + for (int sample = 0; sample < num_of_samples; sample++) { - for (int channel = 0; channel < audio->getNumChannels(); channel++) + for (int channel = 0; channel < num_of_channels; channel++) { // Add sample to output array - output[position] = audio->getSampleData(channel)[sample]; + //cout << position << ", " << channel << ", " << sample << endl; + output[position] = buffer->getSampleData(channel)[sample]; + + if (number == 1) + { + cout << buffer->getSampleData(channel)[sample] << endl; + } // increment position position++; } } + // Update sample count (since it might have changed due to resampling) + *sample_count = num_of_samples; + // return combined array return output; } diff --git a/src/Main.cpp b/src/Main.cpp index 9f12f3c7..2e972905 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -30,11 +30,11 @@ int main() r.DisplayInfo(); // Create a writer - FFmpegWriter w("/home/jonathan/output.mp3"); + FFmpegWriter w("/home/jonathan/output.flac"); w.DisplayInfo(); // Set options - w.SetAudioOptions(true, "libmp3lame", 44100, 2, 64000); + w.SetAudioOptions(true, "flac", 44100, 2, 64000); // Write header w.WriteHeader(); @@ -42,6 +42,7 @@ int main() for (int frame = 1; frame <= 120; frame++) { Frame f = r.GetFrame(frame); + //f.DisplayWaveform(false); // Write frame cout << "Write frame " << f.number << endl;