From 8d46c76ec75905277d04948f13cd5203f0f00eab Mon Sep 17 00:00:00 2001 From: ronag Date: Thu, 18 Aug 2011 14:48:25 +0000 Subject: [PATCH] 2.0. ffmpeg_producer: Added fix for reading FLV meta-data. FFMPEG reads it incorrectly. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1214 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- modules/ffmpeg/ffmpeg.vcxproj | 11 +++ modules/ffmpeg/ffmpeg.vcxproj.filters | 9 ++ modules/ffmpeg/producer/format/flv.cpp | 92 ++++++++++++------- modules/ffmpeg/producer/format/flv.h | 23 +---- .../ffmpeg/producer/video/video_decoder.cpp | 25 ++++- 5 files changed, 103 insertions(+), 57 deletions(-) diff --git a/modules/ffmpeg/ffmpeg.vcxproj b/modules/ffmpeg/ffmpeg.vcxproj index 9fcfaf1a4..cc0f30750 100644 --- a/modules/ffmpeg/ffmpeg.vcxproj +++ b/modules/ffmpeg/ffmpeg.vcxproj @@ -305,6 +305,16 @@ ../../StdAfx.h ../../StdAfx.h + + Use + ../../StdAfx.h + Use + ../../StdAfx.h + Use + ../../StdAfx.h + Use + ../../StdAfx.h + ../StdAfx.h ../StdAfx.h @@ -345,6 +355,7 @@ + diff --git a/modules/ffmpeg/ffmpeg.vcxproj.filters b/modules/ffmpeg/ffmpeg.vcxproj.filters index 9a884cf4b..055aedc01 100644 --- a/modules/ffmpeg/ffmpeg.vcxproj.filters +++ b/modules/ffmpeg/ffmpeg.vcxproj.filters @@ -19,6 +19,9 @@ {4b0f3949-6dc5-4895-837f-4c3ef1759a90} + + {613cfb2a-5714-46dc-b5ad-6964dded5b02} + @@ -55,6 +58,9 @@ source\producer + + source\producer\format + @@ -94,5 +100,8 @@ source\producer\filter + + source\producer\format + \ No newline at end of file diff --git a/modules/ffmpeg/producer/format/flv.cpp b/modules/ffmpeg/producer/format/flv.cpp index 3ebcc8ec0..2d4d56417 100644 --- a/modules/ffmpeg/producer/format/flv.cpp +++ b/modules/ffmpeg/producer/format/flv.cpp @@ -8,6 +8,8 @@ #include +#include + namespace caspar { double to_double(std::vector bytes, bool readInReverse) @@ -26,45 +28,73 @@ double to_double(std::vector bytes, bool readInReverse) return val; } -double next_double(std::fstream& fileStream, int offset, int length) +double next_double(std::fstream& fileStream) { - fileStream.seekg(offset, std::ios::cur); - std::vector bytes(length); - fileStream.read(bytes.data(), length); + std::vector bytes(8); + fileStream.read(bytes.data(), bytes.size()); return to_double(bytes, true); -} +} -flv_meta_info read_flv_meta_info(const std::wstring& filename) +bool next_bool(std::fstream& fileStream) { - if(!boost::filesystem::exists(filename)) - BOOST_THROW_EXCEPTION(caspar_exception()); + std::vector bytes(1); + fileStream.read(bytes.data(), bytes.size()); + return bytes[0] != 0; +} - flv_meta_info meta_info; +std::map read_flv_meta_info(const std::string& filename) +{ + std::map values; - std::fstream fileStream = std::fstream(narrow(filename), std::fstream::in); - fileStream.seekg(27, std::ios::beg); + if(boost::filesystem2::path(filename).extension() != ".flv") + return values; - std::array bytes; - fileStream.read(bytes.data(), bytes.size()); + try + { + if(!boost::filesystem2::exists(filename)) + BOOST_THROW_EXCEPTION(caspar_exception()); + + std::fstream fileStream = std::fstream(filename, std::fstream::in); + fileStream.seekg(27, std::ios::beg); + + std::vector bytes(10); + fileStream.read(bytes.data(), bytes.size()); + + if (std::string(bytes.begin(), bytes.end()) == "onMetaData") + { + fileStream.seekg(6, std::ios::cur); + + for(int n = 0; n < 9; ++n) + { + char name_size = 0; + fileStream.read(&name_size, 1); + + std::vector name(name_size); + fileStream.read(name.data(), name.size()); + auto name_str = std::string(name.begin(), name.end()); + + char data_type = 0; + fileStream.read(&data_type, 1); + + switch(data_type) + { + case 0: + values[name_str] = boost::lexical_cast(next_double(fileStream)); + break; + case 1: + values[name_str] = boost::lexical_cast(next_bool(fileStream)); + break; + } + fileStream.seekg(1, std::ios::cur); + } + } + } + catch(...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + } - auto on_meta_data = std::string(bytes.begin(), bytes.end()); - if (on_meta_data == "onMetaData") - { - //// 16 bytes past "onMetaData" is the data for "duration" - meta_info.duration = next_double(fileStream, 16, 8); - //// 8 bytes past "duration" is the data for "width" - meta_info.width = next_double(fileStream, 8, 8); - //// 9 bytes past "width" is the data for "height" - meta_info.height = next_double(fileStream, 9, 8); - //// 16 bytes past "height" is the data for "videoDataRate" - meta_info.video_data_rate = next_double(fileStream, 16, 8); - //// 16 bytes past "videoDataRate" is the data for "audioDataRate" - meta_info.audio_data_rate = next_double(fileStream, 16, 8); - //// 12 bytes past "audioDataRate" is the data for "frameRate" - meta_info.frame_rate = next_double(fileStream, 12, 8); - } - - return meta_info; + return values; } } \ No newline at end of file diff --git a/modules/ffmpeg/producer/format/flv.h b/modules/ffmpeg/producer/format/flv.h index 8ec2265c4..931e7fffb 100644 --- a/modules/ffmpeg/producer/format/flv.h +++ b/modules/ffmpeg/producer/format/flv.h @@ -1,26 +1,7 @@ #pragma once namespace caspar { - -struct flv_meta_info -{ - double duration; - double width; - double height; - double frame_rate; - double video_data_rate; - double audio_data_rate; - - flv_meta_info() - : duration(0.0) - , width(0.0) - , height(0.0) - , frame_rate(0.0) - , video_data_rate(0.0) - , audio_data_rate(0.0) - {} -}; - -flv_meta_info read_flv_meta_info(const std::wstring& filename); + +std::map read_flv_meta_info(const std::string& filename); } \ No newline at end of file diff --git a/modules/ffmpeg/producer/video/video_decoder.cpp b/modules/ffmpeg/producer/video/video_decoder.cpp index d78361f67..4b3e2bcd4 100644 --- a/modules/ffmpeg/producer/video/video_decoder.cpp +++ b/modules/ffmpeg/producer/video/video_decoder.cpp @@ -21,6 +21,7 @@ #include "video_decoder.h" +#include "../format/flv.h" #include "../util.h" #include "../filter/filter.h" @@ -31,6 +32,7 @@ #include #include +#include #include @@ -88,12 +90,25 @@ public: // Some files give an invalid time_base numerator, try to fix it. if(codec_context_ && codec_context_->time_base.num == 1) codec_context_->time_base.num = static_cast(std::pow(10.0, static_cast(std::log10(static_cast(codec_context_->time_base.den)))-1)); - - nb_frames_ = context->streams[index_]->nb_frames; - if(nb_frames_ == 0) - nb_frames_ = context->streams[index_]->duration;// * context->streams[index_]->time_base.den; + + if(boost::filesystem2::path(context->filename).extension() == ".flv") + { + try + { + auto meta = read_flv_meta_info(context->filename); + fps_ = boost::lexical_cast(meta["framerate"]); + nb_frames_ = static_cast(boost::lexical_cast(meta["duration"])*fps_); + } + catch(...){} + } + else + { + fps_ = static_cast(codec_context_->time_base.den) / static_cast(codec_context_->time_base.num); + nb_frames_ = context->streams[index_]->nb_frames; + if(nb_frames_ == 0) + nb_frames_ = context->streams[index_]->duration;// * context->streams[index_]->time_base.den; + } - fps_ = static_cast(codec_context_->time_base.den) / static_cast(codec_context_->time_base.num); if(double_rate(filter)) fps_ *= 2; -- 2.39.2