Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raii Ejemplo 3 #2

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
build
*.kdev4
.idea
cmake-build-debug/
26 changes: 17 additions & 9 deletions 03-record-sdl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,33 @@ cmake_minimum_required(VERSION 2.6)

project(ffmpeg-sdl)

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -std=c++11")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -std=c++11 -pthread")

add_library(sdldemo
src/Area.cpp
src/SdlTexture.cpp
src/SdlException.cpp
src/SdlWindow.cpp
src/Area.cpp
src/SdlTexture.cpp
src/SdlException.cpp
src/SdlWindow.cpp
)

# Agrego la carpeta con los headers autogenerados a los includes
message("Agregando '${PROJECT_BINARY_DIR}' como directorio de includes")
include_directories(${PROJECT_BINARY_DIR})

add_executable (record-sdl
src/OutputFormat.cpp
src/FormatContext.cpp
src/main.cpp
src/Output.cpp
src/Frame.cpp
src/Packet.cpp
src/FormatOutput.cpp
src/CodecContext.cpp
src/FormatContext.cpp
src/SwsContext.cpp
src/BlockingQueue.cpp
src/Consumer.cpp
src/Thread.cpp
src/main.cpp
)

target_link_libraries(record-sdl avformat avcodec avutil swscale sdldemo SDL2 SDL2_image)

install(FILES assets/cat.gif DESTINATION ${CMAKE_BINARY_DIR})
install(FILES assets/cat.gif DESTINATION ${CMAKE_BINARY_DIR})
48 changes: 48 additions & 0 deletions 03-record-sdl/src/BlockingQueue.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// Created by camix on 12/06/19.
//

#include "BlockingQueue.h"
#include <vector>
#include <iostream>

BlockingQueue::BlockingQueue() {
this->done = false;
}

BlockingQueue::~BlockingQueue() = default;

void BlockingQueue::push(std::vector<char> element) {
std::unique_lock<std::mutex> lock(this->m);
this->queue.push(element);
this->cond_variable.notify_all();
}

void BlockingQueue::close() {
std::vector<char> s;
push(s);
}

std::vector<char> BlockingQueue::pop() {
std::unique_lock<std::mutex> lock(this->m);

if (this->done)
throw BlockingQueueDoneException();
int i = 0;
while (this->queue.empty() && ! this->done) {
this->cond_variable.wait(lock);
i++;
}

if (this->done)
throw BlockingQueueDoneException();

std::vector<char> data = this->queue.front();
this->queue.pop();
if (data.empty()) {
this->done = true;
throw BlockingQueueDoneException();
}
return data;
}

49 changes: 49 additions & 0 deletions 03-record-sdl/src/BlockingQueue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Created by camix on 12/06/19.
//

#ifndef FFMPEG_DEMO_BLOCKINGQUEUE_H
#define FFMPEG_DEMO_BLOCKINGQUEUE_H

#define BQ_CLOSED_EXCEPTION "The queue is closed"

#include <queue>
#include <mutex>
#include <condition_variable>

class BlockingQueue {
private:
std::queue <std::vector<char>> queue;
std::mutex m;
std::condition_variable cond_variable;
bool done;

public:
BlockingQueue();
~BlockingQueue();

//Guarda un elemento en la cola prioritaria.
void push(std::vector<char>);

//Saca un elemento de la cola prioritaria.
//Si la cola esta vacia espera a que se ingrese un elemento.
//Si se termino de encolar elementos se lanza una excepcion.
std::vector<char> pop();

//Cierra la cola.
void close();
};



class BlockingQueueDoneException : public std::exception {
virtual const char* what() const throw () {
std::string message = BQ_CLOSED_EXCEPTION;
return message.c_str();
}

public:
explicit BlockingQueueDoneException() = default;
};

#endif //FFMPEG_DEMO_BLOCKINGQUEUE_H
51 changes: 51 additions & 0 deletions 03-record-sdl/src/CodecContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Created by camix on 10/06/19.
//

extern "C" {
#include <libavutil/opt.h>
}
#include "CodecContext.h"

CodecContext::CodecContext(AVCodec *codec) :
codecContext(avcodec_alloc_context3(codec)) {
if (!codecContext) {
throw CodecContextInitException();
}
// La resolución debe ser múltiplo de 2
this->codecContext->width = 352;
this->codecContext->height = 288;
this->codecContext->time_base = {1,25};
this->codecContext->framerate = {25,1};
this->codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
this->codecContext->gop_size = 10;
this->codecContext->max_b_frames = 2;
if (codec->id == AV_CODEC_ID_H264) {
this->codecContext->profile = FF_PROFILE_H264_BASELINE;
av_opt_set(this->codecContext->priv_data, "preset", "slow", 0);
}
avcodec_open2(this->codecContext, codec, NULL);
}

CodecContext::~CodecContext() {
avcodec_close(this->codecContext);
avcodec_free_context(&this->codecContext);
}


int CodecContext::getPixFmt() {
return this->codecContext->pix_fmt;
}


int CodecContext::getWidth() {
return this->codecContext->width;
}

int CodecContext::getHeight() {
return this->codecContext->height;
}

AVCodecContext* CodecContext::get() {
return this->codecContext;
}
51 changes: 51 additions & 0 deletions 03-record-sdl/src/CodecContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Created by camix on 10/06/19.
//

#ifndef FFMPEG_DEMO_CODECCONTEXT_H
#define FFMPEG_DEMO_CODECCONTEXT_H

#define INIT_CODEC_CONTEXT_EXC "There was an error while allocating memory for a CodecContext\n"
extern "C" {
#include <libavcodec/avcodec.h>
}

#include <string>

class CodecContextException : public std::exception {
protected:
std::string message;
public:
explicit CodecContextException() = default;
virtual const char *what() const throw() {
return this->message.c_str();
}
};

class CodecContextInitException : public CodecContextException {
public:
explicit CodecContextInitException() {
message = INIT_CODEC_CONTEXT_EXC;
}
};

class CodecContext {
private:
AVCodecContext* codecContext;

public:
explicit CodecContext(AVCodec *codec);

~CodecContext();

AVCodecContext *get();

int getHeight();

int getWidth();

int getPixFmt();
};


#endif //FFMPEG_DEMO_CODECCONTEXT_H
12 changes: 12 additions & 0 deletions 03-record-sdl/src/Constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Created by camix on 12/06/19.
//

#ifndef FFMPEG_DEMO_CONSTANTS_H
#define FFMPEG_DEMO_CONSTANTS_H

#define BUFFER_WIDTH 352
#define BUFFER_HEIGHT 288


#endif //FFMPEG_DEMO_CONSTANTS_H
33 changes: 33 additions & 0 deletions 03-record-sdl/src/Consumer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Created by camix on 12/06/19.
//
extern "C" {
#include <libswscale/swscale.h>
}
#include "Consumer.h"
#include "Constants.h"

Consumer::Consumer(BlockingQueue& producedFrames, std::string& filename) :
producedFrames(producedFrames),
videoOutput(context, filename),
ctx(sws_getContext(BUFFER_WIDTH, BUFFER_HEIGHT,
AV_PIX_FMT_RGB24, BUFFER_WIDTH, BUFFER_HEIGHT,
AV_PIX_FMT_YUV420P, 0, 0, 0, 0)) {
}

void Consumer::run() {
try {
while (true) {
std::vector<char> frame = this->producedFrames.pop();
videoOutput.writeFrame(frame.data(), ctx);
}
}
catch (BlockingQueueDoneException& e) {
return;
}
}

Consumer::~Consumer() {
videoOutput.close();
sws_freeContext(ctx);
}
34 changes: 34 additions & 0 deletions 03-record-sdl/src/Consumer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Created by camix on 12/06/19.
//

#ifndef FFMPEG_DEMO_CONSUMER_H
#define FFMPEG_DEMO_CONSUMER_H


#include "Thread.h"
#include "BlockingQueue.h"
#include "Output.h"
#include "FormatContext.h"

class Consumer : public Thread {
private:
BlockingQueue& producedFrames;
FormatContext context;
Output videoOutput;
// You need it to perform scaling/conversion operations using.
SwsContext* ctx;

public:
/// first you need to Initialize libavformat and register all the muxers, demuxers and
/// protocols with av_register_all();
Consumer(BlockingQueue& producedImages, std::string& filename);

~Consumer();

virtual void run() override;

};


#endif //FFMPEG_DEMO_CONSUMER_H
41 changes: 41 additions & 0 deletions 03-record-sdl/src/FormatOutput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Created by camix on 10/06/19.
//
extern "C" {
#include <libavutil/opt.h>
}

#include "FormatOutput.h"
#include "CodecContext.h"

FormatOutput::FormatOutput(const std::string& filename) {
// Intenta deducir formato según extensión
this->avOutputFormat = av_guess_format(NULL, filename.c_str(), NULL);
if (!this->avOutputFormat) {
// Intenta usar el formato standard
this->avOutputFormat = av_guess_format("mpeg", NULL, NULL);
}
if (!this->avOutputFormat) {
throw FormatOutputInitException();
}
// h.264 es bastante popular, pero hay mejores
this->avOutputFormat->video_codec = AV_CODEC_ID_H264;



this->codec = avcodec_find_encoder(this->avOutputFormat->video_codec);
if (!codec) {
throw FormatOutputInitException("No se pudo instanciar codec");
}
//codecContext.init(codec);
}


AVCodec *FormatOutput::getCodec() {
return this->codec;
}


FormatOutput::~FormatOutput() {

}
Loading