diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-09-11 16:11:47 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-09-11 16:11:47 +0100 |
| commit | f9694b7d4f1648a0fa984e7cc428bbc9eea86ca0 (patch) | |
| tree | 59e14e57c52e82927963ef71bf83de0f665c42cb | |
| parent | 1f52520db005e056e131f511418e4b71bc9e89fd (diff) | |
ffms2 library for video loader
| -rwxr-xr-x | install_dependencies_linux.sh | 8 | ||||
| -rw-r--r-- | rotord/Makefile | 2 | ||||
| -rw-r--r-- | rotord/src/ffmpeg-fas_wrapper.h | 16 | ||||
| -rw-r--r-- | rotord/src/graph.cpp | 2 | ||||
| -rw-r--r-- | rotord/src/graph.h | 1 | ||||
| -rw-r--r-- | rotord/src/libavwrapper.cpp | 60 | ||||
| -rw-r--r-- | rotord/src/libavwrapper.h | 64 | ||||
| -rw-r--r-- | rotord/src/ofUtils.o | bin | 0 -> 593072 bytes | |||
| -rw-r--r-- | rotord/src/rendercontext.h | 1 | ||||
| -rw-r--r-- | rotord/src/rotor.cpp | 4 | ||||
| -rw-r--r-- | rotord/src/rotor.h | 71 | ||||
| -rw-r--r-- | rotord/src/seek_indices.h | 94 | ||||
| -rw-r--r-- | working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.cpp (renamed from rotord/src/ffmpeg-fas_wrapper.cpp) | 0 | ||||
| -rw-r--r-- | working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.h | 55 | ||||
| -rw-r--r-- | working/ffmpeg_fas-wrapper/ffmpeg_fas.c (renamed from rotord/src/ffmpeg_fas.c) | 0 | ||||
| -rw-r--r-- | working/ffmpeg_fas-wrapper/ffmpeg_fas.h (renamed from rotord/src/ffmpeg_fas.h) | 0 | ||||
| -rw-r--r-- | working/ffmpeg_fas-wrapper/private_errors.h (renamed from rotord/src/private_errors.h) | 0 | ||||
| -rw-r--r-- | working/ffmpeg_fas-wrapper/seek_indices.c (renamed from rotord/src/seek_indices.c) | 0 |
18 files changed, 254 insertions, 124 deletions
diff --git a/install_dependencies_linux.sh b/install_dependencies_linux.sh index 0cf06bb..803d7fd 100755 --- a/install_dependencies_linux.sh +++ b/install_dependencies_linux.sh @@ -46,6 +46,14 @@ make sudo make install cd .. +git clone https://github.com/FFMS/ffms2.git +cd ffms2/ +./configure +make +sudo make install +cd .. +rm -r ffms2 + LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH sudo ldconfig diff --git a/rotord/Makefile b/rotord/Makefile index 3e5902b..902a95f 100644 --- a/rotord/Makefile +++ b/rotord/Makefile @@ -9,7 +9,7 @@ MY_CFLAGS = -Wswitch -fpermissive -std=c++11 -I /usr/include/opencv -I /usr/incl # -I ../ffmpeg # The linker options.libgstaasinklibgstaasink.so -MY_LIBS = -ljsoncpp -lcairo -lopencv_core -lopencv_video -lopencv_imgproc -lopencv_highgui -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lswscale -lavcodec -lavformat -lavfilter -lavdevice -lavutil -lstdc++ -lm +MY_LIBS = -lffms2 -ljsoncpp -lcairo -lopencv_core -lopencv_video -lopencv_imgproc -lopencv_highgui -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lswscale -lavcodec -lavformat -lavfilter -lavdevice -lavutil -lstdc++ -lm #-lopencv_highgui #MY_LIBS = -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lswscale -lavcodec -lavformat -lavfilter -lavdevice -lavutil $(shell pkg-config gstreamer-0.10 gstreamer-video-0.10 gstreamer-base-0.10 --libs) # -lgstreamer-0.10 -lgstreamer-video-0.10 -lgstreamer-base-0.10 -lglib-2.0 -lgstapp-0.10 diff --git a/rotord/src/ffmpeg-fas_wrapper.h b/rotord/src/ffmpeg-fas_wrapper.h deleted file mode 100644 index dedff62..0000000 --- a/rotord/src/ffmpeg-fas_wrapper.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ffmpeg_fas_wrapper_H -#define ffmpeg_fas_wrapper_H - -#include <string> -#include "ffmpeg_fas.h" - - -namespace ffmpeg_fas { - class decoder - { - public: - bool open(std::string& fileName); - fas_raw_image_type frame; - }; -} -#endif diff --git a/rotord/src/graph.cpp b/rotord/src/graph.cpp index 2e89a4c..5487717 100644 --- a/rotord/src/graph.cpp +++ b/rotord/src/graph.cpp @@ -279,6 +279,7 @@ bool Graph::parseJson(string &data,string &media_path){ } //we know the json validates so clear the existing graph clear(); + Node_factory factory; check_audio(root["audio"].asString(),media_path); init(root["ID"].asString(),root["description"].asString()); Json::Value jnodes = root["nodeDefinitions"]; @@ -394,6 +395,7 @@ bool Graph::parseJson(string &data,string &media_path){ } bool Graph::parseXml(string media_path){ clear(); + Node_factory factory; check_audio(xml.getAttribute("patchbay","audio","",0),media_path); init(xml.getAttribute("patchbay","ID","",0),xml.getValue("patchbay","",0)); if(xml.pushTag("patchbay")) { diff --git a/rotord/src/graph.h b/rotord/src/graph.h index d614b3b..b2132b9 100644 --- a/rotord/src/graph.h +++ b/rotord/src/graph.h @@ -61,7 +61,6 @@ namespace Rotor { bool cancelled; float progress; private: - Node_factory factory; int outW,outH; }; diff --git a/rotord/src/libavwrapper.cpp b/rotord/src/libavwrapper.cpp index b7b5688..321725e 100644 --- a/rotord/src/libavwrapper.cpp +++ b/rotord/src/libavwrapper.cpp @@ -80,8 +80,9 @@ void libav::maybeInitFFMpegLib() { if (b_is_one_time_inited) return; - av_register_all(); - avcodec_register_all(); + FFMS_Init(0, 0); //should do for all + //av_register_all(); + //avcodec_register_all(); avformat_network_init(); b_is_one_time_inited = true; } @@ -556,7 +557,56 @@ bool libav::decoder::avtry(int result, const std::string& msg) { return true; } + void libav::ffms2_decoder::cleanup(){ + if (loaded) { + mutex.lock(); + FFMS_DestroyVideoSource(videosource); + mutex.unlock(); + loaded=false; + } +} +bool libav::ffms2_decoder::open(const std::string& filename){ + mutex.lock(); + loaded=false; + FFMS_Index *index = FFMS_MakeIndex(filename.c_str(), 0, 0, NULL, NULL, FFMS_IEH_ABORT, NULL, NULL, &errinfo); + if (index == NULL) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + int trackno = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_VIDEO, &errinfo); + if (trackno < 0) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + videosource = FFMS_CreateVideoSource(filename.c_str(), trackno, index, 1, FFMS_SEEK_NORMAL, &errinfo); + if (videosource == NULL) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + FFMS_DestroyIndex(index); + videoprops = FFMS_GetVideoProperties(videosource); + const FFMS_Frame *propframe = FFMS_GetFrame(videosource, 0, &errinfo); + w=propframe->EncodedWidth; + h=propframe->EncodedHeight; + //propframe->EncodedPixelFormat; + + if (FFMS_SetOutputFormatV2(videosource, pixfmts, propframe->EncodedWidth, propframe->EncodedHeight, FFMS_RESIZER_BICUBIC, &errinfo)) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + int framenumber = 0; /* valid until next call to FFMS_GetFrame* on the same video object */ + + + std::cerr<<"ffmpegsource: successfully opened "<<filename<<std::endl; + loaded=true; + mutex.unlock(); + return loaded; +} /////////////////////////// // encoder methods // @@ -1245,7 +1295,7 @@ void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream * AVFrame *frame = avcodec_alloc_frame(); int got_packet, ret; - av_init_packet(&pkt); + //av_init_packet(&pkt); 111013 NOT NECESSARY c = st->codec; //get_audio_frame(samples, audio_input_frame_size, c->channels); @@ -1406,7 +1456,7 @@ void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream * if (oc->oformat->flags & AVFMT_RAWPICTURE) { // Raw video case - directly store the picture in the packet // AVPacket pkt; - av_init_packet(&pkt); + //av_init_packet(&pkt); ///removed 101013 NOT NECESSARY pkt.flags |= AV_PKT_FLAG_KEY; pkt.stream_index = st->index; @@ -1418,7 +1468,7 @@ void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream * } else { AVPacket pkt = { 0 }; int got_packet; - av_init_packet(&pkt); + //av_init_packet(&pkt); ///removed 101013 NOT NECESSARY // encode the image // diff --git a/rotord/src/libavwrapper.h b/rotord/src/libavwrapper.h index d30ea95..870815f 100644 --- a/rotord/src/libavwrapper.h +++ b/rotord/src/libavwrapper.h @@ -69,6 +69,8 @@ extern "C" { #include <math.h> #include <vector> +#include <ffms.h> + namespace libav { @@ -154,6 +156,68 @@ namespace libav { }; + class ffms2_decoder + { + public: + ffms2_decoder(){ + maybeInitFFMpegLib(); + pixfmts[0] = FFMS_GetPixFmt("rgb24"); + pixfmts[1] = -1; + h=0; + w=0; + videosource=NULL; + loaded=false; + errinfo.Buffer = errmsg; + errinfo.BufferSize = sizeof(errmsg); + errinfo.ErrorType = FFMS_ERROR_SUCCESS; + errinfo.SubType = FFMS_ERROR_SUCCESS; + } + ~ffms2_decoder(){ + cleanup(); + } + void cleanup(); + bool open(const std::string& filename); + float getFrameRate(){ + if (loaded) return (((float)videoprops->FPSNumerator)/((float)videoprops->FPSDenominator)); + else return -1.0f; + } + int getNumberOfFrames(){ + if (loaded) return videoprops->NumFrames; + else return -1; + } + int getNumberOfChannels(){ + return 3; //this is what we convert to + } + int getWidth(){ + return w; + } + int getHeight(){ + return h; + } + bool fetchFrame(int width,int height,int wanted){ + if (FFMS_SetOutputFormatV2(videosource, pixfmts, width, height, FFMS_RESIZER_BICUBIC, &errinfo)) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + return false; + } + frame = FFMS_GetFrame(videosource, wanted%videoprops->NumFrames, &errinfo); + if (frame == NULL) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + return false; + } + return true; + + } + + FFMS_VideoSource *videosource; + FFMS_VideoProperties *videoprops; + FFMS_Frame *frame; + FFMS_ErrorInfo errinfo; + char errmsg[1024]; + int pixfmts[2]; + bool loaded; + int h,w; + }; + /* // TODO - finish refactoring based on // http://svn.gnumonks.org/trunk/21c3-video/ffmpeg/ffmpeg-0.4.9-pre1/output_example.c diff --git a/rotord/src/ofUtils.o b/rotord/src/ofUtils.o Binary files differnew file mode 100644 index 0000000..d31a12b --- /dev/null +++ b/rotord/src/ofUtils.o diff --git a/rotord/src/rendercontext.h b/rotord/src/rendercontext.h index f15ca31..b525a07 100644 --- a/rotord/src/rendercontext.h +++ b/rotord/src/rendercontext.h @@ -103,7 +103,6 @@ namespace Rotor { Audio_thumbnailer *audio_thumb; Graph graph; - Node_factory factory; float output_framerate; }; diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp index ee18dbd..d26cdec 100644 --- a/rotord/src/rotor.cpp +++ b/rotord/src/rotor.cpp @@ -80,7 +80,7 @@ float Parameter::get(const Time_spec& time){ //gets input and updates variable return value; } -bool Video_loader::load(const string &_filename){ +bool _Video_loader::load(const string &_filename){ Logger& logger = Logger::get("Rotor"); if (isLoaded) { player.cleanup(); ///should be in decoder class? @@ -102,7 +102,7 @@ bool Video_loader::load(const string &_filename){ return false; } -Image* Video_loader::output(const Frame_spec &frame){ +Image* _Video_loader::output(const Frame_spec &frame){ if (isLoaded){ //this approach is running into the inability to seek when requesting playback speed > 1. diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h index eba5be1..ff8675a 100644 --- a/rotord/src/rotor.h +++ b/rotord/src/rotor.h @@ -29,7 +29,6 @@ Definitions of base classes and types for rotor rendering graph #include "utils.h" #include "cvimage.h" #include "libavwrapper.h" -#include "ffmpeg-fas_wrapper.h" //using namespace cv; namespace Rotor { @@ -879,6 +878,33 @@ namespace Rotor { }; #define VIDEOFRAMES_frame 1 #define VIDEOFRAMES_blend 2 + class _Video_loader: public Image_node { + public: + _Video_loader(){ + create_parameter("speed","number","video playback speed","Speed",1.0f,0.0f,0.0f); + create_parameter("framerate","number","framerate override","Frame rate",0.0f,0.0f,0.0f); + create_attribute("filename","name of video file to load","File name",""); + create_attribute("mode","frame mode","Mode","frame",{"frame","blend"}); + title="Video loader"; + description="Loads a video file"; + }; + _Video_loader(map<string,string> &settings): _Video_loader() { + base_settings(settings); + isLoaded=false; + if (attributes["filename"]->value!="") { + load(find_setting(settings,"media_path","")+attributes["filename"]->value); + } + lastframe=0; + }; + ~_Video_loader(){}; + bool load(const string &filename); + Image *output(const Frame_spec &frame); + _Video_loader* clone(map<string,string> &_settings) { return new _Video_loader(_settings);}; + bool isLoaded; + private: + libav::decoder player; + int lastframe; + }; class Video_loader: public Image_node { public: Video_loader(){ @@ -898,12 +924,49 @@ namespace Rotor { lastframe=0; }; ~Video_loader(){}; - bool load(const string &filename); - Image *output(const Frame_spec &frame); + bool load(const string &filename){ + Poco::Logger& logger = Poco::Logger::get("Rotor"); + if (isLoaded) { + player.cleanup(); ///should be in decoder class? + isLoaded=false; + } + isLoaded=player.open(filename); + if (isLoaded){ + logger.information("Video_loader loaded "+filename+": "\ + +toString(player.getNumberOfFrames())+" frames, "\ + +toString(player.getFrameRate())+" fps, "\ + +toString(player.getWidth())+"x"+toString(player.getHeight())\ + +", channels:"+toString(player.getNumberOfChannels())); + return true; + } + logger.error("Video_loader failed to load "+filename); + return false; + } + Image *output(const Frame_spec &frame){ + if (isLoaded){ + float clipframerate=(parameters["framerate"]->value==0.0f?player.getFrameRate():parameters["framerate"]->value); + float clipspeed=(clipframerate/frame.framerate)*parameters["speed"]->value; + int wanted=(((int) ((frame.time*frame.framerate)+0.5))%max(1,player.getNumberOfFrames()-1)); + if (wanted!=lastframe){ + if (!player.fetchFrame(frame.w,frame.h,wanted)) { //seek fail + Poco::Logger& logger = Poco::Logger::get("Rotor"); + logger.error("Video_loader failed to seek frame "+toString(wanted)+" of "+attributes["filename"]->value); + + if (image.w>0) return ℑ //just return the previous frame if possible + else return nullptr; + } + image.setup_fromRGB(frame.w,frame.h,player.frame->Data[0],player.frame->Linesize[0]-(frame.w*3)); + lastframe=wanted; + } + return ℑ + } + return nullptr; + }; Video_loader* clone(map<string,string> &_settings) { return new Video_loader(_settings);}; bool isLoaded; private: - libav::decoder player; + //ffmpegsource::decoder player; + libav::ffms2_decoder player; int lastframe; }; class Video_output: public Image_node { diff --git a/rotord/src/seek_indices.h b/rotord/src/seek_indices.h deleted file mode 100644 index e908979..0000000 --- a/rotord/src/seek_indices.h +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * Copyright 2008. Pittsburgh Pattern Recognition, Inc. - * - * This file is part of the Frame Accurate Seeking extension library to - * ffmpeg (ffmpeg-fas). - * - * ffmpeg-fas is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * The ffmpeg-fas library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#ifndef FAS_SEEK_INDICES_H -#define FAS_SEEK_INDICES_H - -#include <stdint.h> -#include <stdio.h> - -/* If C++ then we need to __extern "C". Compiler defines __cplusplus */ -#ifdef __cplusplus -#define __extern extern "C" -#else -#define __extern extern -#endif - - -/********************************************************************** - * Seek Table Types - **********************************************************************/ - -typedef enum -{ - seek_no_error, - seek_unknown_error, - seek_bad_argument, - seek_malloc_failed, -} seek_error_type; - -typedef enum -{ - seek_false = 0, - seek_true = 1 -} seek_boolean_type; - -typedef struct -{ - int display_index; - int64_t first_packet_dts; - int64_t last_packet_dts; -} seek_entry_type; - -typedef struct -{ - seek_entry_type *array; - seek_boolean_type completed; - int num_frames; // total number of frames - int num_entries; // ie, number of seek-points (keyframes) - int allocated_size; -} seek_table_type; - - - -/********************************************************************** - * Seek Table Functions - **********************************************************************/ - - -__extern seek_table_type seek_init_table (int initial_size); -__extern void seek_release_table (seek_table_type *table); - -__extern seek_table_type seek_copy_table (seek_table_type source); -__extern int compare_seek_tables(seek_table_type t1, seek_table_type t2); - -__extern seek_error_type seek_append_table_entry (seek_table_type *table, seek_entry_type entry); - -__extern seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset); - -__extern seek_error_type seek_show_table (seek_table_type table); /* human readable */ -__extern seek_error_type seek_show_raw_table (FILE *file, seek_table_type table); - -__extern seek_table_type read_table_file(char *name); /* read raw file */ - -#endif - -/**** End of File *****************************************************/ diff --git a/rotord/src/ffmpeg-fas_wrapper.cpp b/working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.cpp index f1b81c2..f1b81c2 100644 --- a/rotord/src/ffmpeg-fas_wrapper.cpp +++ b/working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.cpp diff --git a/working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.h b/working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.h new file mode 100644 index 0000000..4c8f96e --- /dev/null +++ b/working/ffmpeg_fas-wrapper/ffmpeg-fas_wrapper.h @@ -0,0 +1,55 @@ +#ifndef ffmpeg_fas_wrapper_H +#define ffmpeg_fas_wrapper_H + +#include <string> +#include <iostream> +#include "ffmpeg_fas.c" + + +namespace ffmpeg_fas { + class decoder + { + public: + decoder(){ + fas_initialize(FAS_TRUE,FAS_RGB24); + loaded=false; + framerate=0.0f; + numFrames=0; + } + bool open(std::string& filename){ + fas_error_type e=fas_open_video(&context,filename.c_str()); + if (e==FAS_SUCCESS){ + loaded=true; + framerate=(((float)context->format_context->streams[context->stream_idx]->r_frame_rate.num)/((float)context->format_context->streams[context->stream_idx]->r_frame_rate.den)); + numFrames=context->format_context->streams[context->stream_idx]->nb_frames; + if (numFrames<1){ + //some codecs don't keep this info in the header + numFrames = (int)(( context->format_context->duration / (double)AV_TIME_BASE ) * framerate ); + //this approach still doesn't seem to give quite the right answer- comes out a little too big + //could alternatively just redefine the length if the reader fails + } + } + else { + std::cerr<<"ffmpeg_fas ERROR: "<<fas_error_message(e)<<std::endl; + loaded=true; + } + return loaded; + } + float getFrameRate(){ + return framerate; + } + int getNumberOfFrames(); + int getNumberOfChannels(); + int getWidth(); + int getHeight(); + bool fetchFrame(int width,int height,int wanted); + void cleanup(); //necessary? + + fas_raw_image_type frame; + fas_context_ref_type context; + bool loaded; + float framerate; + int numFrames; + }; +} +#endif diff --git a/rotord/src/ffmpeg_fas.c b/working/ffmpeg_fas-wrapper/ffmpeg_fas.c index 19e9655..19e9655 100644 --- a/rotord/src/ffmpeg_fas.c +++ b/working/ffmpeg_fas-wrapper/ffmpeg_fas.c diff --git a/rotord/src/ffmpeg_fas.h b/working/ffmpeg_fas-wrapper/ffmpeg_fas.h index 0c51103..0c51103 100644 --- a/rotord/src/ffmpeg_fas.h +++ b/working/ffmpeg_fas-wrapper/ffmpeg_fas.h diff --git a/rotord/src/private_errors.h b/working/ffmpeg_fas-wrapper/private_errors.h index 9369ae3..9369ae3 100644 --- a/rotord/src/private_errors.h +++ b/working/ffmpeg_fas-wrapper/private_errors.h diff --git a/rotord/src/seek_indices.c b/working/ffmpeg_fas-wrapper/seek_indices.c index cb877c3..cb877c3 100644 --- a/rotord/src/seek_indices.c +++ b/working/ffmpeg_fas-wrapper/seek_indices.c |
