From 1ef20ee017b11272e6b241a40e3413becaf4c0d6 Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Mon, 25 Mar 2013 13:40:59 +0000 Subject: much progress with audio format --- rotord/Makefile | 2 +- rotord/rotor.cpp | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++----- rotord/rotor.h | 31 ++++++++-- 3 files changed, 187 insertions(+), 22 deletions(-) (limited to 'rotord') diff --git a/rotord/Makefile b/rotord/Makefile index 3ccbfc2..d153562 100644 --- a/rotord/Makefile +++ b/rotord/Makefile @@ -1,5 +1,5 @@ # The pre-processor and compiler options. -MY_CFLAGS = -fpermissive -std=c++11 +MY_CFLAGS = -fpermissive -std=c++11 -Wno-error # -I ../ffmpeg diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index b8c5e2f..de9f4ea 100644 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -32,8 +32,10 @@ void Render_context::runTask() { //audio_analyser.process(audio_filename); //vampHost::runPlugin("","qm-vamp-plugins","qm-tempotracker", "",0, audio_filename, cerr,true); vector proc; + proc.push_back(new audio_thumbnailer()); if (load_audio(audio_filename,proc)) { state=AUDIO_READY; + //set the response } else state=IDLE; } @@ -290,6 +292,7 @@ bool Render_context::load_audio(const string &filename,vector avFormat(avformat_alloc_context(), &avformat_free_context); @@ -358,13 +361,12 @@ bool Render_context::load_audio(const string &filename,vectorsample_rate <<", channels: "<channels<<", sample format: "<sample_fmt<index) - continue; // the packet is not about the stream we want, let's jump again the start of the loop - } while(0); - */ + // suspect why was this in twice 210313 + //do { + // if (packet.packet.stream_index != stream->index) + /// continue; // the packet is not about the stream we want, let's jump again the start of the loop + //} while(0); + // // allocating an AVFrame std::shared_ptr avFrame(avcodec_alloc_frame(), &av_free); @@ -406,22 +408,22 @@ bool Render_context::load_audio(const string &filename,vectorsample_fmt) * CHAR_BIT; // 16 or 32 - unsigned int numberOfChannels = stream.codecContext->channels; // 1 for mono, 2 for stereo, or more - unsigned int numberOfSamplesContainedInTheFrame = stream.frame->nb_samples * stream.codecContext->channels; - unsigned int numberOfSamplesToPlayPerSecond = stream.codecContext->sample_rate; // usually 44100 or 48000 - const void* data = stream.frame->data[0]; - */ + + //unsigned int bitsPerSample = av_get_bytes_per_sample(stream.codecContext->sample_fmt) * CHAR_BIT; // 16 or 32 + //unsigned int numberOfChannels = stream.codecContext->channels; // 1 for mono, 2 for stereo, or more + //unsigned int numberOfSamplesContainedInTheFrame = stream.frame->nb_samples * stream.codecContext->channels; + //unsigned int numberOfSamplesToPlayPerSecond = stream.codecContext->sample_rate; // usually 44100 or 48000 + //const void* data = stream.frame->data[0]; + if (processedLength < 0) { //av_free_packet(&packet); shouldn't have to because of type safe wrapper - cerr <<"Error while processing the data"<< endl; + cerr <<"Error "<nb_streams; ++i) + { + if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + { + audioStream = formatContext->streams[i]; + break; + } } + if (audioStream == NULL) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Could not find any audio stream in the file" << std::endl; + return false; + } + + AVCodecContext* codecContext = audioStream->codec; + + codecContext->codec = avcodec_find_decoder(codecContext->codec_id); + if (codecContext->codec == NULL) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Couldn't find a proper decoder" << std::endl; + return false; + } + else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Couldn't open the context with the decoder" << std::endl; + return false; + } + + av_dump_format(formatContext, 0, 0, false); //avformat.h line 1256 + int samples = ((formatContext->duration + 5000)*codecContext->sample_rate)/AV_TIME_BASE; + + std::cout << "This stream has " << codecContext->channels << " channels, a sample rate of " << codecContext->sample_rate << "Hz and "<sample_fmt<< " (aka "<< av_get_sample_fmt_name(codecContext->sample_fmt) << ") "<init(codecContext->channels,16,samples); + } + + AVPacket packet; + av_init_packet(&packet); + + // Read the packets in a loop + while (av_read_frame(formatContext, &packet) == 0) + { + if (packet.stream_index == audioStream->index) + { + // Try to decode the packet into a frame + int frameFinished = 0; + int bytes = avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet); + + // Some frames rely on multiple packets, so we have to make sure the frame is finished before + // we can use it + if (frameFinished) + { + // frame now has usable audio data in it. How it's stored in the frame depends on the format of + // the audio. If it's packed audio, all the data will be in frame->data[0]. If it's in planar format, + // the data will be in frame->data and possibly frame->extended_data. Look at frame->data, frame->nb_samples, + // frame->linesize, and other related fields on the FFmpeg docs. I don't know how you're actually using + // the audio data, so I won't add any junk here that might confuse you. Typically, if I want to find + // documentation on an FFmpeg structure or function, I just type " doxygen" into google (like + // "AVFrame doxygen" for AVFrame's docs) + + //std::cout << "Got a frame: bytes " << bytes << std::endl; + //now we can pass the data to the processor(s) + for (auto p: processors) { + p->process_frame(frame->data[0],frame->nb_samples); + } + + } + } + + // You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory + av_free_packet(&packet); + } + + // Some codecs will cause frames to be buffered up in the decoding process. If the CODEC_CAP_DELAY flag + // is set, there can be buffered up frames that need to be flushed, so we'll do that + if (codecContext->codec->capabilities & CODEC_CAP_DELAY) + { + av_init_packet(&packet); + // Decode all the remaining frames in the buffer, until the end is reached + int frameFinished = 0; + int bytes = avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet); + while (bytes >= 0 && frameFinished) + { + for (auto p: processors) { + p->process_frame(frame->data[0],frame->nb_samples); + } + } + } + + // Clean up! + av_free(frame); + avcodec_close(codecContext); + av_close_input_file(formatContext); + + + return true; } diff --git a/rotord/rotor.h b/rotord/rotor.h index c08371d..132059f 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -335,17 +335,38 @@ namespace Rotor { }; class base_audio_processor { public: - 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) { + virtual bool process_frame(uint8_t *data,int samples)=0; + void init(int _channels,int _bits,int _samples) { channels=_channels; bits=_bits; + samples=_samples; }; - int channels,bits; + int channels,bits,samples; }; class audio_thumbnailer: public base_audio_processor { + //how to deal with the fact that frames don't correspond with pixels? + //buffer the data somehow + //draw pixels based on rms value public: + audio_thumbnailer(){ + height=64; + width=512; + data=new uint8_t[height*width]; + memset(data,0,height*width); + } + ~audio_thumbnailer(){ + delete[] data; + } + void init(int _channels,int _bits,int _samples) { + base_audio_processor::init(_channels,_bits,_samples); + samples_per_column=samples/width(); + } + bool process_frame(uint8_t *data,int samples){ + + return true; + } + uint8_t *data; + int height,width,samples_per_column; }; class Render_context: public Poco::Task { //Poco task object //manages a 'patchbay' -- cgit v1.2.3