diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index 3eb5de81..abb5036b 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -64,6 +64,7 @@ namespace openshot AVStream *pStream, *aStream; AVPacket packet; AVFrame *pFrame; + ReSampleContext *resampleCtx; bool check_interlace; bool check_fps; bool init_settings; diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 3d2171ff..753702d9 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -5,7 +5,8 @@ using namespace openshot; FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, InvalidCodec) : last_video_frame(0), last_audio_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), audio_pts_offset(99999), video_pts_offset(99999), working_cache(50), path(path), - is_video_seek(true), check_interlace(false), check_fps(false), init_settings(false), enable_seek(true) { + is_video_seek(true), check_interlace(false), check_fps(false), init_settings(false), + enable_seek(true), resampleCtx(NULL) { // Open the file (if possible) Open(); @@ -116,6 +117,8 @@ void FFmpegReader::Close() avcodec_close(pCodecCtx); if (info.has_audio) avcodec_close(aCodecCtx); + if (resampleCtx) + audio_resample_close(resampleCtx); // Close the video file av_close_input_file(pFormatCtx); @@ -480,13 +483,45 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int } // Calculate total number of samples - packet_samples += (buf_size / sizeof(int16_t)); + packet_samples += (buf_size / (av_get_bits_per_sample_format(aCodecCtx->sample_fmt) / 8)); // process samples... packet.data += used; packet.size -= used; } + + // Re-sample audio samples (if needed) + if(aCodecCtx->sample_fmt != SAMPLE_FMT_S16) { + // Audio needs to be converted + if(!resampleCtx) + // Create an audio resample context object (used to convert audio samples) + resampleCtx = av_audio_resample_init( + info.channels, + info.channels, + info.sample_rate, + info.sample_rate, + SAMPLE_FMT_S16, + aCodecCtx->sample_fmt, + 0, 0, 0, 0.0f); + + if (!resampleCtx) + throw InvalidCodec("Failed to convert audio samples to 16 bit (SAMPLE_FMT_S16).", path); + else + { + // create a new array (to hold the re-sampled audio) + int16_t converted_audio[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; + + // Re-sample audio + audio_resample(resampleCtx, (short *)&converted_audio, (short *)&audio_buf, packet_samples); + + // Copy audio samples over original samples + memcpy(&audio_buf, (uint8_t *)&converted_audio, packet_samples); + } + } + + + for (int channel_filter = 0; channel_filter < info.channels; channel_filter++) { // Array of floats (to hold samples for each channel) @@ -508,24 +543,9 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // Only add samples for current channel if (channel_filter == channel) { - // Add sample (convert from (-32768 to 32768) to (-1.0 to 1.0)) channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 15)); - - // Experimental audio conversion -// switch (aCodecCtx->sample_fmt) -// { -// case SAMPLE_FMT_U8: -// channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 7)); -// case SAMPLE_FMT_S16: -// channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 15)); -// case SAMPLE_FMT_S32: -// channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 31)); -// case SAMPLE_FMT_FLT: -// channel_buffer[position] = audio_buf[sample]; -// case SAMPLE_FMT_DBL: -// channel_buffer[position] = audio_buf[sample]; -// } + //cout << channel << "\t" << channel_buffer[position] << endl; // Increment audio position position++; @@ -546,6 +566,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // Loop through samples, and add them to the correct frames int start = starting_sample; int remaining_samples = channel_buffer_size; + float *iterate_channel_buffer = channel_buffer; while (remaining_samples > 0) { // Create or get frame object @@ -558,14 +579,22 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int samples = remaining_samples; // Add samples for current channel to the frame - f.AddAudio(channel_filter, start, channel_buffer, samples, 1.0f); + cout << "starting_frame_number: " << starting_frame_number << endl; + cout << "channel_filter: " << channel_filter << endl; + cout << "samples: " << samples << endl; + cout << "remaining_samples: " << remaining_samples << endl; + f.AddAudio(channel_filter, start, iterate_channel_buffer, samples, 1.0f); // Update working cache - working_cache.Add(starting_frame_number, f); + working_cache.Add(f.number, f); // Decrement remaining samples remaining_samples -= samples; + // Increment buffer (to next set of samples) + if (remaining_samples > 0) + iterate_channel_buffer += samples; + // Increment frame number starting_frame_number++; @@ -576,6 +605,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // clear channel buffer delete channel_buffer; channel_buffer = NULL; + iterate_channel_buffer = NULL; } } diff --git a/src/Main.cpp b/src/Main.cpp index 21cc50ee..f8e6b180 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -16,7 +16,7 @@ int main() // openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/test.mp4"); // openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/test1.mp4"); - openshot::FFmpegReader r("/home/jonathan/Videos/Version 1.1a.mp4"); + openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/piano.wav"); // openshot::FFmpegReader r("/home/jonathan/Videos/sintel-1024-stereo.mp4"); // openshot::FFmpegReader r("/home/jonathan/Videos/00001.mts"); // openshot::FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4"); @@ -29,7 +29,7 @@ int main() // Display debug info r.DisplayInfo(); - for (int frame = 300; frame < 3000; frame++) + for (int frame = 1; frame < 3000; frame++) { Frame f = r.GetFrame(frame); f.Play();