Skip to content

Commit

Permalink
[libav] Getting there
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Dec 31, 2023
1 parent b0c603c commit 3e5764c
Show file tree
Hide file tree
Showing 7 changed files with 579 additions and 138 deletions.
120 changes: 40 additions & 80 deletions src/plugins/score-plugin-gfx/Gfx/Libav/LibavEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,89 +10,35 @@ extern "C" {
#if SCORE_HAS_LIBAV
namespace Gfx
{
LibavEncoder::LibavEncoder()
LibavEncoder::LibavEncoder(const LibavOutputSettings& set)
: m_set{set}
{
av_dict_set(&opt, "fflags", "nobuffer", 0);
av_dict_set(&opt, "flags", "low_delay", 0);
for(const auto& [k, v] : set.options)
{
av_dict_set(&opt, k.toStdString().c_str(), v.toStdString().c_str(), 0);
}
if(!opt)
av_dict_set(&opt, "", "", 0);
}

LibavEncoder::~LibavEncoder()
{
av_dict_free(&opt);
}

void LibavEncoder::enumerate()
{
#if 0
// enumerate all codecs and put into list
std::vector<const AVCodec*> encoderList;
AVCodec* codec = nullptr;
while(codec = av_codec_next(codec))
{
// try to get an encoder from the system
auto encoder = avcodec_find_encoder(codec->id);
if(encoder)
{
encoderList.push_back(encoder);
}
}
// enumerate all containers
AVOutputFormat* outputFormat = nullptr;
while(outputFormat = av_oformat_next(outputFormat))
{
for(auto codec : encoderList)
{
// only add the codec if it can be used with this container
if(avformat_query_codec(outputFormat, codec->id, FF_COMPLIANCE_STRICT) == 1)
{
// add codec for container
}
}
}
#endif
}

void LibavEncoder::encode(
AVCodecContext* enc_ctx, AVFrame* frame, AVPacket* pkt, FILE* outfile)
{
int ret;

/* send the frame to the encoder */
if(frame)
printf("Send frame %3" PRId64 "\n", frame->pts);

ret = avcodec_send_frame(enc_ctx, frame);
if(ret < 0)
{
fprintf(stderr, "Error sending a frame for encoding\n");
exit(1);
}

while(ret >= 0)
{
ret = avcodec_receive_packet(enc_ctx, pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if(ret < 0)
{
fprintf(stderr, "Error during encoding\n");
exit(1);
}

printf("Write packet %3" PRId64 " (size=%5d)\n", pkt->pts, pkt->size);
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
}

int LibavEncoder::start()
{
const char* filename = "/tmp/tata.mp4";
int ret = avformat_alloc_output_context2(&m_formatContext, NULL, NULL, filename);
const auto muxer = m_set.muxer.toStdString();
const auto filename = m_set.path.toStdString();
int ret = avformat_alloc_output_context2(
&m_formatContext, nullptr, muxer.c_str(), filename.c_str());

if(ret < 0 || !m_formatContext)
{
fprintf(stderr, "Could not create format for '%s': %s\n", filename, av_err2str(ret));
fprintf(
stderr, "Could not create format for '%s' - '%s': %s\n", muxer.c_str(),
filename.c_str(), av_err2str(ret));
m_formatContext = nullptr;
return 1;
}

Expand All @@ -105,39 +51,45 @@ int LibavEncoder::start()
// fmt->video_codec: default video codec for mkv
auto default_audio_encoder = avcodec_find_encoder(fmt->audio_codec);
auto default_video_encoder = avcodec_find_decoder(fmt->video_codec);
qDebug() << "Codec:" << default_audio_encoder->name << default_video_encoder->name;
if(default_audio_encoder)
qDebug() << "Default Audio Codec:" << default_audio_encoder->name;
if(default_video_encoder)
qDebug() << "Default Video Codec:" << default_video_encoder->name;

// For each parameter:
// Add a streamr
{
StreamOptions opts;
opts.codec = "libx264rgb";
streams.emplace_back(m_formatContext, opts);
opts.codec = m_set.video_encoder_short
.toStdString(); // FIXME need to pass a codec id instead
streams.emplace_back(m_set, m_formatContext, opts);
}

// For all streams:
// Open them
for(auto& stream : streams)
{
stream.open(m_formatContext, stream.codec, opt);
stream.open(m_set, m_formatContext, stream.codec, opt);
}

// Dump all streams
{
int k = 0;
for(auto& stream : streams)
{
av_dump_format(m_formatContext, k++, filename, true);
av_dump_format(m_formatContext, k++, filename.c_str(), true);
}
}

// If it's a file fopen it
if(!(fmt->flags & AVFMT_NOFILE))
{
ret = avio_open(&m_formatContext->pb, filename, AVIO_FLAG_WRITE);
ret = avio_open(&m_formatContext->pb, filename.c_str(), AVIO_FLAG_WRITE);
if(ret < 0)
{
fprintf(stderr, "Could not open '%s': %s\n", filename, av_err2str(ret));
fprintf(stderr, "Could not open '%s': %s\n", filename.c_str(), av_err2str(ret));
avformat_free_context(m_formatContext);
m_formatContext = nullptr;
return 1;
}
}
Expand All @@ -147,6 +99,8 @@ int LibavEncoder::start()
if(ret < 0)
{
fprintf(stderr, "Error occurred when opening output file: %s\n", av_err2str(ret));
avformat_free_context(m_formatContext);
m_formatContext = nullptr;
return 1;
}
return 0;
Expand All @@ -157,7 +111,11 @@ int LibavEncoder::add_frame(
{
auto& stream = streams[0];
auto next_frame = stream.get_video_frame();

next_frame->format = fmt;
next_frame->width = width;
next_frame->height = height;
next_frame->data[0] = (unsigned char*)data;
/*
auto out = next_frame->data[0];
for(int y = 0; y < height; y++)
{
Expand All @@ -167,10 +125,11 @@ int LibavEncoder::add_frame(
out[1] = data[1];
out[2] = data[2];
out += 3;
out += 4;
data += 4;
}
}
*/
return streams[0].write_video_frame(m_formatContext, next_frame);
}

Expand All @@ -187,8 +146,9 @@ int LibavEncoder::stop()
streams.clear();

if(!(fmt->flags & AVFMT_NOFILE))
{
avio_closep(&m_formatContext->pb);

}
avformat_free_context(m_formatContext);
m_formatContext = nullptr;

Expand Down
6 changes: 3 additions & 3 deletions src/plugins/score-plugin-gfx/Gfx/Libav/LibavEncoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <Media/Libav.hpp>
#if SCORE_HAS_LIBAV

#include <Gfx/Libav/LibavOutputSettings.hpp>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
Expand All @@ -16,17 +16,17 @@ namespace Gfx
struct OutputStream;
struct LibavEncoder
{
LibavEncoder();
explicit LibavEncoder(const LibavOutputSettings& set);
~LibavEncoder();
void enumerate();
void encode(AVCodecContext* enc_ctx, AVFrame* frame, AVPacket* pkt, FILE* outfile);

int start();
int add_frame(const unsigned char* data, AVPixelFormat fmt, int width, int height);
int stop();

bool available() const noexcept { return m_formatContext; }

LibavOutputSettings m_set;
AVDictionary* opt = NULL;
AVFormatContext* m_formatContext{};

Expand Down
5 changes: 1 addition & 4 deletions src/plugins/score-plugin-gfx/Gfx/Libav/LibavEncoderNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ LibavEncoderNode::LibavEncoderNode(
, m_settings{set}
{
input.push_back(new score::gfx::Port{this, {}, score::gfx::Types::Image, {}});
m_settings.width = 1280;
m_settings.height = 720;
m_settings.rate = 60;
}

LibavEncoderNode::~LibavEncoderNode() { }
Expand Down Expand Up @@ -57,7 +54,7 @@ void LibavEncoderNode::render()
if(bytes > 0 && bytes >= sz)
{
encoder.add_frame(
(const unsigned char*)m_readback.data.constData(), AV_PIX_FMT_RGB24,
(const unsigned char*)m_readback.data.constData(), AV_PIX_FMT_RGBA,
m_readback.pixelSize.width(), m_readback.pixelSize.height());
}
}
Expand Down
Loading

0 comments on commit 3e5764c

Please sign in to comment.