summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorComment <tim@gray.(none)>2013-03-17 19:17:29 +0000
committerComment <tim@gray.(none)>2013-03-17 19:17:29 +0000
commit156f40773fae82ec9fe8b5c7ad2615d8fa60c22e (patch)
treeafb9f5730aac06a59c3ca53adbc0e693269125ba
parent23fe664dabce0a7aa1890d2968e304b2ea666320 (diff)
implementing decoder
-rw-r--r--rotord/avCodec.cpp2
-rw-r--r--rotord/avCodec.h8
-rw-r--r--rotord/rotor.cpp124
-rwxr-xr-xrotord/rotor.h37
4 files changed, 124 insertions, 47 deletions
diff --git a/rotord/avCodec.cpp b/rotord/avCodec.cpp
index 61c201b..36b92a6 100644
--- a/rotord/avCodec.cpp
+++ b/rotord/avCodec.cpp
@@ -308,7 +308,7 @@ static void avCodec::video_encode_example(const char *filename, int codec_id)
printf("Encode video file %s\n", filename);
/* find the mpeg1 video encoder */
- codec =avcodec_find_encoder(codec_id);
+ codec =avcodec_find_encoder((AVCodecID)codec_id);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
diff --git a/rotord/avCodec.h b/rotord/avCodec.h
index 7e1815a..23f45f8 100644
--- a/rotord/avCodec.h
+++ b/rotord/avCodec.h
@@ -24,12 +24,12 @@ extern "C" {
namespace avCodec {
static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
- static int select_sample_rate(AVCodec *codec);
- static int select_channel_layout(AVCodec *codec);
- static void audio_encode_example(const char *filename);
static void audio_decode_example(const char *outfilename, const char *filename);
- static void video_encode_example(const char *filename, int codec_id);
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,char *filename);
static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,AVFrame *frame, int *frame_count, AVPacket *pkt, int last);
+ static int select_channel_layout(AVCodec *codec);
+ static void video_encode_example(const char *filename, int codec_id);
+ static void audio_encode_example(const char *filename);
+ static int select_sample_rate(AVCodec *codec);
static void video_decode_example(const char *outfilename, const char *filename);
} \ No newline at end of file
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp
index feb4a6c..281671e 100644
--- a/rotord/rotor.cpp
+++ b/rotord/rotor.cpp
@@ -31,7 +31,8 @@ void Render_context::runTask() {
state=ANALYSING_AUDIO;
//audio_analyser.process(audio_filename);
//vampHost::runPlugin("","qm-vamp-plugins","qm-tempotracker", "",0, audio_filename, cerr,true);
- load_audio(audio_filename);
+ vector<base_audio_processor*> proc;
+ load_audio(audio_filename,proc);
state=AUDIO_READY;
}
@@ -290,42 +291,11 @@ Command_response Render_context::session_command(const std::vector<std::string>&
//YES
//http://blog.tomaka17.com/2012/03/libavcodeclibavformat-tutorial/
-
-static int open_codec_context(int *stream_idx,AVFormatContext *fmt_ctx, enum AVMediaType type)
-{
- int ret;
- AVStream *st;
- AVCodecContext *dec_ctx = NULL;
- AVCodec *dec = NULL;
- ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
- if (ret < 0) {
- fprintf(stderr, "Could not find %s stream in input file \n",
- av_get_media_type_string(type));
- return ret;
- } else {
- *stream_idx = ret;
- st = fmt_ctx->streams[*stream_idx];
- /* find decoder for the stream */
- dec_ctx = st->codec;
- dec = avcodec_find_decoder(dec_ctx->codec_id);
- cerr << "Looking for decoder for codec "<< dec_ctx->codec_id<<endl;
- if (!dec) {
- fprintf(stderr, "Failed to find %s codec\n",
- av_get_media_type_string(type));
- return ret;
- }
- if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
- fprintf(stderr, "Failed to open %s codec\n",
- av_get_media_type_string(type));
- return ret;
- }
- }
- return 0;
-}
+//great to use c++11 features
-bool Render_context::load_audio(string &filename){
+bool Render_context::load_audio(string &filename,vector<base_audio_processor*> processors){
//load audio data from file
//what's the best way to use this? the model is background processing, and we want to update a progress bar
//could pass a function pointer to call when each chunk of data becomes available?
@@ -341,19 +311,19 @@ bool Render_context::load_audio(string &filename){
auto avFormatPtr = avFormat.get();
if (avformat_open_input(&avFormatPtr,filename.c_str(),nullptr, nullptr) != 0) {
- cerr <<"Error while calling avformat_open_input (probably invalid file format)" << endl;
+ cerr <<"Rotor: Error while calling avformat_open_input (probably invalid file format)" << endl;
return false;
}
if (avformat_find_stream_info(avFormat.get(), nullptr) < 0) {
- cerr << "Error while calling avformat_find_stream_info" << endl;
+ cerr << "Rotor: Error while calling avformat_find_stream_info" << endl;
return false;
}
av_dump_format(avFormat.get(), 0, 0, false);
AVStream* stream = nullptr;
- for (auto i = 0; i < avFormat->nb_streams; ++i) {
+ for (unsigned int i = 0; i < avFormat->nb_streams; ++i) {
if (avFormat->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
// we've found a video stream!
stream = avFormat->streams[i];
@@ -361,11 +331,89 @@ bool Render_context::load_audio(string &filename){
}
}
if (!stream) {
- cerr <<"Didn't find any audio stream in the file"<< endl;
+ cerr <<"Rotor: Didn't find any audio stream in the file"<< endl;
return false;
}
+ // getting the required codec structure
+ const auto codec = avcodec_find_decoder(stream->codec->codec_id);
+ if (codec == nullptr) {
+ cerr <<"Rotor: Audio codec not available"<< endl;
+ return false;
+ }
+
+ // allocating a structure
+ std::shared_ptr<AVCodecContext> audioCodec(avcodec_alloc_context3(codec), [](AVCodecContext* c) { avcodec_close(c); av_free(c); });
+
+ /* extradata???
+ // we need to make a copy of videoStream->codec->extradata and give it to the context
+ // make sure that this vector exists as long as the avVideoCodec exists
+ std::vector codecContextExtraData(stream->codec->extradata, stream->codec->extradata + stream->codec->extradata_size);
+ audioCodec->extradata = reinterpret_cast(codecContextExtraData.data());
+ audioCodec->extradata_size = codecContextExtraData.size();
+
+ // initializing the structure by opening the codec
+ if (avcodec_open2(avVideoCodec.get(), codec, nullptr) < 0) {
+ cerr <<"Rotor: Could not open codec"<< endl;
+ return false;
+ }
+ */
+
+ Packet packet(avFormat.get());
+ if (packet.packet.data == nullptr) {
+ //done
+ return true;
+ }
+
+ do {
+ packet.reset(avFormat.get());
+ if (packet.packet.stream_index != stream->index)
+ continue; // the packet is not about the video stream we want, let's jump again the start of the loop
+ } while(0);
+
+ // allocating an AVFrame
+ std::shared_ptr<AVFrame> avFrame(avcodec_alloc_frame(), &av_free);
+
+ // the current packet of data
+ Packet packet;
+ // data in the packet of data already processed
+ size_t offsetInData = 0;
+
+ // the decoding loop, running until EOF
+ while (true) {
+ // reading a packet using libavformat
+ if (offsetInData >= packet.packet.size) {
+ do {
+ packet.reset(avFormat.get());
+ if (packet.stream_index != videoStream->index)
+ continue;
+ } while(0);
+ }
+
+ // preparing the packet that we will send to libavcodec
+ AVPacket packetToSend;
+ packetToSend.data = packet.packet.data + offsetInData;
+ packetToSend.size = packet.packet.size - offsetInData;
+
+ // sending data to libavcodec
+ int isFrameAvailable = 0;
+ const auto processedLength = avcodec_decode_video2(avVideoCodec.get(), avFrame.get(), &isFrameAvailable, &packetToSend);
+ if (processedLength < 0) {
+ av_free_packet(&packet);
+ throw std::runtime_error("Error while processing the data");
+ }
+ offsetInData += processedLength;
+
+ // processing the image if available
+ if (isFrameAvailable) {
+ // display image on the screen
+
+ // sleeping until next frame
+ const auto msToWait = avVideoContext->ticks_per_frame * 1000 * avVideoContext->time_base.num / avVideoContext->time_base.den;
+ std::this_thread::sleep(std::chrono::milliseconds(msToWait));
+ }
+ }
return true;
}
diff --git a/rotord/rotor.h b/rotord/rotor.h
index 18b1f19..c7d25b2 100755
--- a/rotord/rotor.h
+++ b/rotord/rotor.h
@@ -7,6 +7,8 @@ we traverse the graph as recursive function calls until we satisfy all dependenc
NO NODE HAS MORE THAN ONE OUTPUT
WE DON'T LINK TO AN OUTPUT OBJECT WE LINK TO THE NODE - GET_OUTPUT IS THE RENDER FUNCTION
+MORE THAN ONE NODE CAN LINK THE SAME OUTPUT
+NODES CACHE AT LEAST ONE FRAME
??the only node with more than 1 output is audio?
??lets rethink this
@@ -104,6 +106,33 @@ namespace Rotor {
//forward declaration
class Node;
class Signal_node;
+
+ //http://blog.tomaka17.com/2012/03/libavcodeclibavformat-tutorial/
+ struct Packet {
+ explicit Packet(AVFormatContext* ctxt = nullptr) {
+ av_init_packet(&packet);
+ packet.data = nullptr;
+ if (ctxt) reset(ctxt);
+ }
+
+ Packet(Packet&& other) : packet(std::move(other.packet)) {
+ other.packet.data = nullptr;
+ }
+
+ ~Packet() {
+ if (packet.data)
+ av_free_packet(&packet);
+ }
+
+ void reset(AVFormatContext* ctxt) {
+ if (packet.data)
+ av_free_packet(&packet);
+ if (av_read_frame(ctxt, &packet) < 0)
+ packet.data = nullptr;
+ }
+
+ AVPacket packet;
+ };
class Render_status{
@@ -304,14 +333,14 @@ namespace Rotor {
base_audio_processor();
base_audio_processor(int _channels,int _bits);
virtual bool process_chunk(char *data,int num_samples);
+ void init(int _channels,int _bits) {
+ channels=_channels;
+ bits=_bits;
+ };
int channels,bits;
};
class audio_thumbnailer: public base_audio_processor {
public:
- audio_thumbnailer(int _channels,int _bits) {
- channels=_channels;
- bits=_bits;
- };
};
class Render_context: public Poco::Task { //Poco task object
//manages a 'patchbay'