Making mosaic images with ffmpeg
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.7 KiB

#include <image_io.hpp>
#include <utilities.hpp>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
using namespace std;
static void save_as_jpg(av::frame const & frame, std::string const & filename){
const auto pix_fmt = AV_PIX_FMT_YUVJ444P;
const auto codec_id= AV_CODEC_ID_MJPEG;
// Convert
int tile_width = 800;
int tile_height = 600;
int h_tiles = 8;
int v_tiles = 6;
std::vector<uint8_t, av::allocator<uint8_t>> data(make_u(avpicture_get_size(pix_fmt, h_tiles * tile_width, v_tiles * tile_height)), 0);
av::frame converted_frame = av::frame_alloc();
avpicture_fill(reinterpret_cast<AVPicture*>(converted_frame.get()), data.data(), pix_fmt, h_tiles * tile_width, v_tiles * tile_height);
converted_frame->width = h_tiles * tile_width;
converted_frame->height = v_tiles * tile_height;
converted_frame->format = pix_fmt;
auto sws_context = sws_getContext(frame->width, frame->height, av::get_format(frame), tile_width, tile_height, av::get_format(converted_frame), 0, nullptr, nullptr, nullptr);
if(!sws_context) throw std::runtime_error("boem sws context");
av::frame cropped_frame = av::frame_clone(converted_frame);
for(int r = 0; r < v_tiles; ++r) {
for(int c = 0; c < h_tiles; ++c){
av_picture_crop(reinterpret_cast<AVPicture*>(cropped_frame.get()), reinterpret_cast<AVPicture*>(converted_frame.get()), av::get_format(converted_frame), r * tile_height, c * tile_width);
sws_scale (sws_context, {frame->data}, {frame->linesize}, 0, frame->height, {cropped_frame->data}, {cropped_frame->linesize});
}
}
sws_freeContext(sws_context);
// Encode
auto codec = avcodec_find_encoder(codec_id);
if(!codec) throw av::error("Could not find codec");
auto codec_ctx = std::unique_ptr<AVCodecContext, av::deleter<AVCodecContext>>(avcodec_alloc_context3(codec), [](auto x){ avcodec_free_context(&x); });
if(!codec_ctx) throw av::error("Could not allocate codec context");
codec_ctx->pix_fmt = pix_fmt;
codec_ctx->width = converted_frame->width;
codec_ctx->height = converted_frame->height;
codec_ctx->time_base = av_make_q(1, 1);
auto opened_codec = av::codec_open(codec_ctx.get(), codec, nullptr);
const auto buffer_size = avpicture_get_size(pix_fmt, codec_ctx->width, codec_ctx->height);
std::vector<uint8_t> buffer(make_u(buffer_size), 0);
auto output_size = avcodec_encode_video(codec_ctx.get(), buffer.data(), buffer_size, converted_frame.get());
assert(output_size <= buffer_size);
cout << "output size" << output_size << endl;
auto file = fopen(filename.c_str(), "wb");
fwrite(buffer.data(), 1, make_u(output_size), file);
fclose(file);
}
int main(){
av_register_all();
while(true){
auto image = open_image("needle.png");
save_as_jpg(image, "output.jpg");
}
}