diff options
Diffstat (limited to 'rotord/ofxMovieExporter.cpp')
| -rwxr-xr-x | rotord/ofxMovieExporter.cpp | 426 |
1 files changed, 0 insertions, 426 deletions
diff --git a/rotord/ofxMovieExporter.cpp b/rotord/ofxMovieExporter.cpp deleted file mode 100755 index 15abfe2..0000000 --- a/rotord/ofxMovieExporter.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* - * ofxMovieExporter.cpp - * - * Copyright (c) 2011, Neil Mendoza, http://www.neilmendoza.com - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of 16b.it nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ -#include "ofxMovieExporter.h" -//#include "ofThread.h" - - const std::string ofxMovieExporter::FILENAME_PREFIX = "capture"; - const std::string ofxMovieExporter::CONTAINER = "mov"; - - ofxMovieExporter::ofxMovieExporter() { - outputFormat = NULL; - formatCtx = NULL; - videoStream = NULL; - - codec = NULL; - codecCtx = NULL; - convertCtx = NULL; - - inPixels = NULL; - outPixels = NULL; - encodedBuf = NULL; - - inFrame = NULL; - outFrame = NULL; - - // do one time encoder set up - av_register_all(); - - } - - bool ofxMovieExporter::setup( - int outW, - int outH, - int bitRate, - int frameRate, - AVCodecID codecId, - std::string container) - { - if (outW % 2 == 1 || outH % 2 == 1) { - cerr << "ofxMovieExporter: Resolution must be a multiple of 2" << endl; - return false; - } - - this->outW = outW; - this->outH = outH; - this->frameRate = frameRate; - this->bitRate = bitRate; - this->codecId = codecId; - this->container = container; - - frameInterval = 1.f / (float)frameRate; - - // HACK HACK HACK - // Time not syncing - // probably related to codec ticks_per_frame - //frameInterval /= 3.f; - - recording = false; - numCaptures = 0; - - inW=outW; - inH=outH; - - convertCtx = sws_getContext(inW, inH, PIX_FMT_RGB24, outW, outH, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); - - allocateMemory(); - - return true; - } - - ofxMovieExporter::~ofxMovieExporter() - { - if (recording) finishRecord(); - - //stopThread(true); - clearMemory(); - } - - bool ofxMovieExporter::record(std::string filePrefix, std::string folderPath) - { - initEncoder(); - - std::ostringstream oss; - oss << folderPath; - if (folderPath != "" && (folderPath[folderPath.size()-1] != '/' && folderPath[folderPath.size()-1] != '\\')) - oss << "/"; - oss << filePrefix << numCaptures << "." << container; - outFileName = oss.str(); - - // open the output file - //if (url_fopen(&formatCtx->pb, outFileName.c_str(), 'wb' ) < 0) //url_fopen URL_WRONLY - // ofLog(OF_LOG_ERROR, "ofxMovieExporter: Could not open file %s", outFileName.c_str()); - if (avio_open(&formatCtx->pb, outFileName.c_str(), AVIO_FLAG_WRITE) < 0) { - cerr << "ofxMovieExporter: Could not open file "<< outFileName<<endl; - return false; - } - - - //ofAddListener(ofEvents.draw, this, &ofxMovieExporter::checkFrame); - - AVDictionary *options; //= NULL; causes a forward declaration error!? - options=NULL; - // write the stream header, if any - avformat_write_header(formatCtx,&options); - - lastFrameTime = 0; - aframeNum = 0; - vframeNum = 0; - recording = true; - - return true; - } - - void ofxMovieExporter::stop() - { - - recording = false; - numCaptures++; - - } - - void ofxMovieExporter::setPixelSource(unsigned char* pixels, int w, int h) - { - - if (pixels == NULL) - { - //ofLog(OF_LOG_ERROR, "ofxMovieExporter: Could not set NULL pixel source"); - return; - } - pixelSource = pixels; - inW = w; - inH = h; - usePixelSource = true; - - // resetup encoder etc - setup(outW, outH, bitRate, frameRate, codecId, container); - } - - - int ofxMovieExporter::getNumCaptures() - { - return numCaptures; - } - - void ofxMovieExporter::resetNumCaptures() - { - numCaptures = 0; - } - -// PRIVATE - - void ofxMovieExporter::finishRecord() - { - av_write_trailer(formatCtx); - - // free the encoder - avcodec_close(codecCtx); - for(int i = 0; i < formatCtx->nb_streams; i++) - { - av_freep(&formatCtx->streams[i]->codec); - av_freep(&formatCtx->streams[i]); - } - av_free(formatCtx); - formatCtx = NULL; - //url_fclose(formatCtx->pb); - } - - void ofxMovieExporter::encodeFrame() - { - - avpicture_fill((AVPicture*)inFrame, inPixels, PIX_FMT_RGB24, inW, inH); - avpicture_fill((AVPicture*)outFrame, outPixels, PIX_FMT_YUV420P, outW, outH); - - //perform the conversion for RGB to YUV and size - sws_scale(convertCtx, inFrame->data, inFrame->linesize, 0, inH, outFrame->data, outFrame->linesize); - - int outSize = avcodec_encode_video(codecCtx, encodedBuf, ENCODED_FRAME_BUFFER_SIZE, outFrame); - if (outSize > 0) - { - AVPacket pkt; - av_init_packet(&pkt); - //pkt.pts = av_rescale_q(codecCtx->coded_frame->pts, codecCtx->time_base, videoStream->time_base); - //if(codecCtx->coded_frame->key_frame) pkt.flags |= AV_PKT_FLAG_KEY; - //pkt.pts = frameNum;//ofGetFrameNum();//codecCtx->coded_frame->pts; - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.dts = pkt.pts; - pkt.stream_index = videoStream->index; - pkt.data = encodedBuf; - pkt.size = outSize; - av_write_frame(formatCtx, &pkt); - } - - vframeNum++; - } - - bool ofxMovieExporter::encodeFrame(unsigned char *pixels) - { - - if (pixels==nullptr) return false; - - //is it possible to skip the first avpicture_fill? - - avpicture_fill((AVPicture*)inFrame, pixels, PIX_FMT_RGB24, inW, inH); - avpicture_fill((AVPicture*)outFrame, outPixels, PIX_FMT_YUV420P, outW, outH); - - //perform the conversion for RGB to YUV and size - sws_scale(convertCtx, inFrame->data, inFrame->linesize, 0, inH, outFrame->data, outFrame->linesize); - - - AVPacket pkt; - int outSize = avcodec_encode_video(codecCtx, encodedBuf, ENCODED_FRAME_BUFFER_SIZE, outFrame); - if (outSize > 0) - { - - av_init_packet(&pkt); - pkt.pts = (int64_t)vframeNum*(frameInterval*(((float)videoStream->time_base.den)/videoStream->time_base.num));//ofGetFrameNum();//codecCtx->coded_frame->pts; - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.dts = pkt.pts; - pkt.stream_index = videoStream->index; - pkt.data = encodedBuf; - pkt.size = outSize; - av_interleaved_write_frame(formatCtx, &pkt); - - vframeNum++; - } - - - //is it as simple as writing an audio packet for every video packet? - // avcodec_encode_audio2(AVCodecContext *avctx,AVPacket *avpkt,const AVFrame *frame,int *got_packet_ptr); - AVPacket apkt; - av_init_packet(&apkt); - apkt.pts = (int64_t)aframeNum*(aframeInterval*(((float)videoStream->time_base.den)/videoStream->time_base.num));//ofGetFrameNum();//codecCtx->coded_frame->pts; - - while(apkt.pts<pkt.pts) { - apkt.flags |= AV_PKT_FLAG_KEY; - apkt.dts = apkt.pts; - apkt.stream_index = audioStream->index; - //apkt.data = encodedBuf; - apkt.size = outSize; - - AVFrame* afrm=avcodec_alloc_frame(); - afrm->nb_samples=44100/25; - afrm->format=AV_SAMPLE_FMT_S16; - uint8_t *d=new uint8_t[afrm->nb_samples*2*2]; - afrm->data[0]=d; - - int gpp; - - //avcodec_fill_audio_frame(afrm, 2, AV_SAMPLE_FMT_S16,(uint8_t *)d,(44100/25) * 2 * 2,1); - - int audioOutSize = avcodec_encode_audio2(acodecCtx,&apkt,afrm,&gpp); - - av_interleaved_write_frame(formatCtx, &apkt); - - aframeNum++; - apkt.pts = (int64_t)aframeNum*(aframeInterval*(((float)videoStream->time_base.den)/videoStream->time_base.num));//ofGetFrameNum();//codecCtx->coded_frame->pts; - } - - - return true; - } - - void ofxMovieExporter::allocateMemory() - { - // clear if we need to reallocate - if(inPixels) - clearMemory(); - - inPixels = new unsigned char[inW * inH * 3]; -//#endif - inFrame = avcodec_alloc_frame(); - - // allocate output stuff - int outSize = avpicture_get_size(PIX_FMT_YUV420P, outW, outH); - outPixels = (unsigned char*)av_malloc(outSize); - outFrame = avcodec_alloc_frame(); - - encodedBuf = (unsigned char*)av_malloc(ENCODED_FRAME_BUFFER_SIZE); - } - - void ofxMovieExporter::clearMemory() { - delete[] inPixels; - - inPixels = NULL; - - av_free(inFrame); - av_free(outFrame); - av_free(encodedBuf); - av_free(outPixels); - - inFrame = NULL; - outFrame = NULL; - encodedBuf = NULL; - outPixels = NULL; - } - - void ofxMovieExporter::initEncoder() - { - ///////////////////////////////////////////////////////////// - // find codec - codec = avcodec_find_encoder(codecId); - //if (!codec) ofLog(OF_LOG_ERROR, "ofxMovieExporter: Codec not found"); - - - - //////////////////////////////////////////////////////////// - // auto detect the output format from the name. default is mpeg. - ostringstream oss; - oss << "amovie." << container; - outputFormat = av_guess_format(NULL, oss.str().c_str(), NULL); - //if (!outputFormat) ofLog(OF_LOG_ERROR, "ofxMovieExporter: Could not guess output container for an %s file (ueuur!!)", container.c_str()); - // set the format codec (the format also has a default codec that can be read from it) - outputFormat->video_codec = codec->id; - - acodec = avcodec_find_encoder(outputFormat->audio_codec); - //---------------------------> - //leaving the audio codec at the default for now - //---------------------------> - - ///////////////////////////////////////////////////////////// - // allocate the format context - formatCtx = avformat_alloc_context(); - //if (!formatCtx) ofLog(OF_LOG_ERROR, "ofxMovieExporter: Could not allocate format context"); - formatCtx->oformat = outputFormat; - - - - ///////////////////////////////////////////////////////////// - // set up the video stream - videoStream = avformat_new_stream(formatCtx,codec); - //videoStream = av_new_stream(formatCtx, 0); - - - ///////////////////////////////////////////////////////////// - // init codec context for video - codecCtx = videoStream->codec; - codecCtx->bit_rate = bitRate; - codecCtx->width = outW; - codecCtx->height = outH; - - codecCtx->time_base.num = 1;//codecCtx->ticks_per_frame; - codecCtx->time_base.den = frameRate; - videoStream->time_base = codecCtx->time_base; - //audioStream->time_base = codecCtx->time_base; //???has the capability of crashing - - codecCtx->gop_size = 10; /* emit one intra frame every ten frames */ - codecCtx->pix_fmt = PIX_FMT_YUV420P; - - if (codecCtx->codec_id == CODEC_ID_MPEG1VIDEO) - { - /* needed to avoid using macroblocks in which some coeffs overflow - this doesnt happen with normal video, it just happens here as the - motion of the chroma plane doesnt match the luma plane */ - codecCtx->mb_decision=2; - } - // some formats want stream headers to be seperate - if(!strcmp(formatCtx->oformat->name, "mp4") || !strcmp(formatCtx->oformat->name, "mov") || !strcmp(formatCtx->oformat->name, "3gp")) - codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; - - // set the output parameters (must be done even if no parameters). - //if ( - // - // - // ??????? - - //av_set_parameters(formatCtx, NULL); - // - // - // - // - - // < 0) ofLog(OF_LOG_ERROR, "ofxMovieExproter: Could not set format parameters"); - - AVDictionary *options; //= NULL; causes a forward declaration error!? - options=NULL; - // open codec - //if ( - avcodec_open2(codecCtx, codec,&options); - // < 0) ofLog(OF_LOG_ERROR, "ofxMovieExproter: Could not open codec"); - - //do all the same for audio? - audioStream = av_new_stream(formatCtx, 1); //??? - acodecCtx = audioStream->codec; - acodecCtx->sample_rate=44100; - acodecCtx->sample_fmt=AV_SAMPLE_FMT_S16; - acodecCtx->channels=2; - acodecCtx->channel_layout=AV_CH_LAYOUT_STEREO; - avcodec_open2(acodecCtx, acodec,&options); - - if (outputFormat->flags & AVFMT_GLOBALHEADER) { - videoStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; - audioStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; - } - - - av_dump_format(formatCtx, 0, oss.str().c_str(), 1); - } - |
