Many small improvements, bug fixes, and build system fixes for newer systems that have both qt4 and qt5.

This commit is contained in:
Jonathan Thomas
2013-09-08 16:08:56 -05:00
parent 12ca79ce0b
commit a42e257521
11 changed files with 175 additions and 67 deletions

View File

@@ -9,65 +9,66 @@
# FindAvformat
FIND_PATH( AVFORMAT_INCLUDE_DIR libavformat/avformat.h
PATHS /usr/include/
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
PATHS /usr/include/
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
FIND_LIBRARY( AVFORMAT_LIBRARY avformat
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
#FindAvcodec
FIND_PATH( AVCODEC_INCLUDE_DIR libavcodec/avcodec.h
PATHS /usr/include/
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
FIND_LIBRARY( AVCODEC_LIBRARY avcodec
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
#FindAvutil
FIND_PATH( AVUTIL_INCLUDE_DIR libavutil/avutil.h
PATHS /usr/include/
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
FIND_LIBRARY( AVUTIL_LIBRARY avutil
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
#FindAvdevice
FIND_PATH( AVDEVICE_INCLUDE_DIR libavdevice/avdevice.h
PATHS /usr/include/
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
FIND_LIBRARY( AVDEVICE_LIBRARY avdevice
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
#FindSwscale
FIND_PATH( SWSCALE_INCLUDE_DIR libswscale/swscale.h
PATHS /usr/include/
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
/usr/include/ffmpeg/
$ENV{FFMPEGDIR}/include/
$ENV{FFMPEGDIR}/include/ffmpeg/ )
FIND_LIBRARY( SWSCALE_LIBRARY swscale
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
PATHS /usr/lib/
/usr/lib/ffmpeg/
$ENV{FFMPEGDIR}/lib/
$ENV{FFMPEGDIR}/lib/ffmpeg/ )
SET( FFMPEG_FOUND FALSE )
@@ -121,4 +122,4 @@ include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(FFMPEG DEFAULT_MSG
FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIR)
FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIR)

12
doc/known_bugs.txt Normal file
View File

@@ -0,0 +1,12 @@
These are the known bugs in the OpenShot Library
-------------------------------------------------
1) (CRITICAL) FFmpegReader - Issues with audio continuity and GetAudioPTSLocation(). For some reason, there are skipped
audio samples, gaps in PTS timecodes, and generally "Poppy" and "Crackly" audio in WebM files. WebM files
seem to have more audio issues than other codecs, for some reason.
2) (CRITICAL) FFmpegReader - Issues with OpenMP and the nested ImageMagick++ OpenMP implementation. On my 8 core system,
If I don't call omp_set_num_threads(4... or less), an ImageMagick++ error is raised. I have posted this
issue on the ImageMagick forum: http://www.imagemagick.org/discourse-server/viewtopic.php?f=23&t=24036
3) (CRITICAL) FFmpegReader - OpenMP issue if more tasks are created than the number of processors. For example, on
ReadStream(), if minimum_packets = 8 and omp_set_num_threads(4), than potentially more than 4 tasks will
be running at the same time, and some tasks just seem to disappear (or never actually start).
4)

View File

@@ -58,6 +58,7 @@ namespace openshot
FFmpegReader *local_reader;
chunk_location previous_location;
ChunkVersion version;
tr1::shared_ptr<Frame> last_frame;
/// Check if folder path existing
bool does_folder_exist(string path);

View File

@@ -92,6 +92,7 @@ namespace openshot
AVPacket *packet;
AVPicture *pFrame;
bool is_open;
bool is_duration_known;
bool check_interlace;
bool check_fps;

View File

@@ -29,7 +29,8 @@ include_directories(${SDL_INCLUDE_DIR})
################# QT4 ###################
# Find QT4 libraries
FIND_PACKAGE(Qt4 REQUIRED)
SET(QT_QMAKE_EXECUTABLE '/usr/bin/qmake-qt4') # DEBUB, WORK-AROUND: Force the use of QT4 (when multiple versions are installed)
FIND_PACKAGE(Qt4)
# Include Qt headers (needed for compile)
include(${QT_USE_FILE})

View File

@@ -214,8 +214,14 @@ tr1::shared_ptr<Frame> ChunkReader::GetFrame(int requested_frame) throw(ReaderCl
previous_location = location;
}
// Return the frame (from the current reader)
return local_reader->GetFrame(location.frame);
// Get the frame (from the current reader)
last_frame = local_reader->GetFrame(location.frame);
// Update the frame number property
last_frame->number = requested_frame;
// Return the frame
return last_frame;
}

View File

@@ -10,7 +10,7 @@
using namespace openshot;
ChunkWriter::ChunkWriter(string path, FileReaderBase *reader) throw (InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory) :
local_reader(reader), path(path), chunk_size(24 * 3), chunk_count(1), frame_count(1), is_writing(false),
local_reader(reader), path(path), chunk_size(24*3), chunk_count(1), frame_count(1), is_writing(false),
default_extension(".webm"), default_vcodec("libvpx"), default_acodec("libvorbis")
{
// Init FileInfo struct (clear all values)
@@ -62,22 +62,21 @@ void ChunkWriter::WriteFrame(tr1::shared_ptr<Frame> frame)
// Create FFmpegWriter (FINAL quality)
create_folder(get_chunk_path(chunk_count, "final", ""));
writer_final = new FFmpegWriter(get_chunk_path(chunk_count, "final", default_extension));
writer_final->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.audio_bit_rate);
writer_final->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, 128000);
writer_final->SetVideoOptions(true, default_vcodec, info.fps, info.width, info.height, info.pixel_ratio, false, false, info.video_bit_rate);
// Create FFmpegWriter (PREVIEW quality)
create_folder(get_chunk_path(chunk_count, "preview", ""));
writer_preview = new FFmpegWriter(get_chunk_path(chunk_count, "preview", default_extension));
writer_preview->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.audio_bit_rate);
writer_preview->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, 128000);
writer_preview->SetVideoOptions(true, default_vcodec, info.fps, info.width * 0.5, info.height * 0.5, info.pixel_ratio, false, false, info.video_bit_rate * 0.5);
// Create FFmpegWriter (LOW quality)
create_folder(get_chunk_path(chunk_count, "thumb", ""));
writer_thumb = new FFmpegWriter(get_chunk_path(chunk_count, "thumb", default_extension));
writer_thumb->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.audio_bit_rate);
writer_thumb->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, 128000);
writer_thumb->SetVideoOptions(true, default_vcodec, info.fps, info.width * 0.25, info.height * 0.25, info.pixel_ratio, false, false, info.video_bit_rate * 0.25);
// Prepare Streams
writer_final->PrepareStreams();
writer_preview->PrepareStreams();
@@ -97,12 +96,22 @@ void ChunkWriter::WriteFrame(tr1::shared_ptr<Frame> frame)
writer_preview->WriteFrame(frame);
writer_thumb->WriteFrame(frame);
// Increment frame counter
frame_count++;
// Write the frames once it reaches the correct chunk size
if (frame_count % chunk_size == 0 && frame_count >= chunk_size)
{
cout << "Done with chunk" << endl;
cout << "frame_count: " << frame_count << endl;
cout << "chunk_size: " << chunk_size << endl;
// Pad an additional 12 frames
for (int z = 0; z<12; z++)
{
// Repeat frame
writer_final->WriteFrame(frame);
writer_preview->WriteFrame(frame);
writer_thumb->WriteFrame(frame);
}
// Write Footer
writer_final->WriteTrailer();
writer_preview->WriteTrailer();
@@ -120,6 +129,9 @@ void ChunkWriter::WriteFrame(tr1::shared_ptr<Frame> frame)
is_writing = false;
}
// Increment frame counter
frame_count++;
// Keep track of the last frame added
last_frame = frame;
}
@@ -156,6 +168,39 @@ void ChunkWriter::WriteFrame(int start, int length)
// Close the writer
void ChunkWriter::Close()
{
// Write the frames once it reaches the correct chunk size
if (is_writing)
{
cout << "Final chunk" << endl;
cout << "frame_count: " << frame_count << endl;
cout << "chunk_size: " << chunk_size << endl;
// Pad an additional 12 frames
for (int z = 0; z<12; z++)
{
// Repeat frame
writer_final->WriteFrame(last_frame);
writer_preview->WriteFrame(last_frame);
writer_thumb->WriteFrame(last_frame);
}
// Write Footer
writer_final->WriteTrailer();
writer_preview->WriteTrailer();
writer_thumb->WriteTrailer();
// Close writer & reader
writer_final->Close();
writer_preview->Close();
writer_thumb->Close();
// Increment chunk count
chunk_count++;
// Stop writing chunk
is_writing = false;
}
// Reset frame counters
chunk_count = 0;
frame_count = 0;

View File

@@ -7,7 +7,7 @@ FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, Inval
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), prev_samples(0), prev_pts(0),
pts_total(0), pts_counter(0), display_debug(false) {
pts_total(0), pts_counter(0), display_debug(false), is_duration_known(false) {
// Init FileInfo struct (clear all values)
InitFileInfo();
@@ -273,12 +273,32 @@ void FFmpegReader::UpdateVideoInfo()
// Set the duration in seconds, and video length (# of frames)
info.duration = pStream->duration * info.video_timebase.ToDouble();
// Check for valid duration
// Check for valid duration (if found)
if (info.duration <= 0.0f && pFormatCtx->duration >= 0)
// Use the format's duration
info.duration = pFormatCtx->duration / AV_TIME_BASE;
info.video_length = round(info.duration * info.fps.ToDouble());
// Calculate duration from filesize and bitrate (if any)
if (info.duration <= 0.0f && info.video_bit_rate > 0 && info.file_size > 0)
// Estimate from bitrate, total bytes, and framerate
info.duration = (info.file_size / info.video_bit_rate);
// No duration found in stream of file
if (info.duration <= 0.0f)
{
// No duration is found in the video stream
info.duration = -1;
info.video_length = -1;
is_duration_known = false;
}
else
{
// Yes, a duration was found
is_duration_known = true;
// Calculate number of frames
info.video_length = round(info.duration * info.fps.ToDouble());
}
// Override an invalid framerate
if (info.fps.ToFloat() > 120.0f)
@@ -295,7 +315,9 @@ void FFmpegReader::UpdateVideoInfo()
tr1::shared_ptr<Frame> FFmpegReader::GetFrame(int requested_frame) throw(ReaderClosed, TooManySeeks)
{
//cout << "GET FRAME " << requested_frame << ", last_frame: " << last_frame << endl;
if (display_debug)
cout << "GET FRAME " << requested_frame << ", last_frame: " << last_frame << endl;
// Check for open reader (or throw exception)
if (!is_open)
throw ReaderClosed("The FFmpegReader is closed. Call Open() before calling this method.", path);
@@ -311,20 +333,20 @@ tr1::shared_ptr<Frame> FFmpegReader::GetFrame(int requested_frame) throw(ReaderC
// Adjust for a requested frame that is too small or too large
if (requested_frame < 1)
requested_frame = 1;
if (requested_frame > info.video_length)
if (requested_frame > info.video_length && is_duration_known)
requested_frame = info.video_length;
if (info.has_video && info.video_length == 0)
// Invalid duration of video file
throw InvalidFile("Could not detect the duration of the video or audio stream.", path);
// Reset seek count
seek_count = 0;
// Check for first frame (always need to get frame 1 before other frames, to correctly calculate offsets)
if (last_frame == 0 && requested_frame != 1)
// Get first frame
ReadStream(1);
// Reset seek count
seek_count = 0;
// Are we within 30 frames of the requested frame?
int diff = requested_frame - last_frame;
if (diff >= 1 && diff <= 30)
@@ -366,12 +388,13 @@ tr1::shared_ptr<Frame> FFmpegReader::ReadStream(int requested_frame)
// Minimum number of packets to process (for performance reasons)
int packets_processed = 0;
int minimum_packets = omp_get_num_procs();
//omp_set_num_threads(1);
int minimum_packets = omp_get_num_procs() / 2; // DEBUG, WORK-AROUND for an ImageMagick bug (preventing use of all 8 cores)
omp_set_num_threads(minimum_packets); // DEBUG, WORK-AROUND for an ImageMagick bug (preventing use of all 8 cores)
omp_set_nested(true);
#pragma omp parallel
{
#pragma omp single
{
// Loop through the stream until the correct frame is found

View File

@@ -329,7 +329,7 @@ void FFmpegWriter::write_queued_frames()
spooled_video_frames.clear();
spooled_audio_frames.clear();
//omp_set_num_threads(1);
omp_set_num_threads(4);
omp_set_nested(true);
#pragma omp parallel
{

View File

@@ -20,10 +20,26 @@ void FrameReady(int number)
int main(int argc, char* argv[])
{
// Create a chunkwriter
//FFmpegReader *r3 = new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4");
//ChunkWriter cw1("/home/jonathan/apps/chunks/chunk1/", r3);
//cw1.WriteFrame(r3, 1, r3->info.video_length);
//cw1.Close();
// FFmpegReader *r3 = new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4");
// r3->DisplayInfo();
// ChunkWriter cw1("/home/jonathan/apps/chunks/chunk1/", r3);
// cw1.WriteFrame(r3, 1, r3->info.video_length);
// cw1.Close();
// return 0;
// FFmpegReader to test 1 part of a chunk
// FFmpegReader *r10 = new FFmpegReader("/home/jonathan/apps/chunks/chunk1/final/000001.webm");
// r10->enable_seek = false;
// r10->Open();
//// r10->GetFrame(1)->Display();
//// r10->GetFrame(2)->Display();
//// r10->GetFrame(3)->Display();
//// r10->GetFrame(1)->Display();
// for (int z1 = 20; z1 <= 24*3; z1++)
// if (z1 >= 65)
// r10->GetFrame(z1)->DisplayWaveform();
// return 0;
// Create a chunkreader
cout << "Start Chunk Reader" << endl;
@@ -35,11 +51,11 @@ int main(int argc, char* argv[])
//cr1.GetFrame(300)->Display();
/* WRITER ---------------- */
FFmpegWriter w9("/home/jonathan/fromchunks.webm");
FFmpegWriter w9("/home/jonathan/fromchunks.mp3");
// Set options
w9.SetAudioOptions(true, cr1.info.acodec, cr1.info.sample_rate, cr1.info.channels, cr1.info.audio_bit_rate);
w9.SetVideoOptions(true, cr1.info.vcodec, cr1.info.fps, cr1.info.width, cr1.info.height, cr1.info.pixel_ratio, false, false, cr1.info.video_bit_rate);
w9.SetAudioOptions(true, "libmp3lame", cr1.info.sample_rate, cr1.info.channels, cr1.info.audio_bit_rate);
//w9.SetVideoOptions(true, cr1.info.vcodec, cr1.info.fps, cr1.info.width, cr1.info.height, cr1.info.pixel_ratio, false, false, cr1.info.video_bit_rate);
// Prepare Streams
w9.PrepareStreams();
@@ -57,6 +73,7 @@ int main(int argc, char* argv[])
cout << "End Chunk Reader" << endl;
return 0;
// Qt Test Code
if (argc == 2)

View File

@@ -35,6 +35,7 @@ include_directories(${SDL_INCLUDE_DIR})
################# QT4 ###################
# Find QT4 libraries
SET(QT_QMAKE_EXECUTABLE '/usr/bin/qmake-qt4') # DEBUB, WORK-AROUND: Force the use of QT4 (when multiple versions are installed)
FIND_PACKAGE(Qt4 REQUIRED)
# Include Qt headers (needed for compile)