removed very situational video_man from raii namespace
This commit is contained in:
parent
21500bf41e
commit
f62f3ceca5
100
include/libav/codec/context.hpp
Normal file
100
include/libav/codec/context.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
#ifndef LIBAV_CODEC_CONTEXT_HPP
|
||||
#define LIBAV_CODEC_CONTEXT_HPP
|
||||
|
||||
#include "libav/fmt/context.hpp"
|
||||
|
||||
#include <utility> //exchange
|
||||
|
||||
extern "C"{
|
||||
# include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
namespace libav::codec{
|
||||
|
||||
class context
|
||||
{
|
||||
private:
|
||||
AVCodecContext* m_context = nullptr;
|
||||
const AVCodec* m_codec = nullptr;
|
||||
bool m_open = false;
|
||||
public:
|
||||
context(const libav::fmt::input_context& ctx, int index){
|
||||
AVCodecParameters* cparms = ctx->streams[index]->codecpar;
|
||||
m_codec = avcodec_find_decoder(cparms->codec_id);
|
||||
m_context = avcodec_alloc_context3(m_codec);
|
||||
if(!m_context)
|
||||
return;
|
||||
avcodec_parameters_to_context(m_context, cparms);
|
||||
}
|
||||
context(const libav::fmt::output_context& ctx, int index){
|
||||
AVCodecParameters* cparms = ctx->streams[index]->codecpar;
|
||||
m_codec = avcodec_find_encoder(cparms->codec_id);
|
||||
m_context = avcodec_alloc_context3(m_codec);
|
||||
if(!m_context)
|
||||
return;
|
||||
avcodec_parameters_to_context(m_context, cparms);
|
||||
}
|
||||
context(const AVCodec* codec){
|
||||
m_codec = codec;
|
||||
m_context = avcodec_alloc_context3(m_codec);
|
||||
}
|
||||
context(const context&) = delete;
|
||||
context(context&& c)noexcept:
|
||||
m_context(std::exchange(c.m_context, nullptr)),
|
||||
m_codec(c.m_codec),
|
||||
m_open(c.m_open){}
|
||||
~context(void){
|
||||
reset();
|
||||
}
|
||||
|
||||
context& operator=(const context&) = delete;
|
||||
context& operator=(context&& c)noexcept{
|
||||
std::swap(m_context, c.m_context);
|
||||
m_codec = c.m_codec;
|
||||
std::swap(m_open, c.m_open);
|
||||
return *this;
|
||||
}
|
||||
bool open(void){
|
||||
int ret = avcodec_open2(m_context, m_codec, NULL);
|
||||
return (m_open = (ret >= 0));
|
||||
}
|
||||
void reset(void){
|
||||
if(m_open)
|
||||
avcodec_close(m_context);
|
||||
if(m_context)
|
||||
avcodec_free_context(&m_context);
|
||||
m_open = false;
|
||||
m_context = nullptr;
|
||||
m_codec = nullptr;
|
||||
}
|
||||
AVCodecContext* release(void){
|
||||
return std::exchange(m_context, nullptr);
|
||||
}
|
||||
|
||||
AVCodecContext* operator->(void){
|
||||
return m_context;
|
||||
}
|
||||
const AVCodecContext* operator->(void)const{
|
||||
return m_context;
|
||||
}
|
||||
|
||||
AVCodecContext* get(void){
|
||||
return m_context;
|
||||
}
|
||||
const AVCodecContext* get(void)const{
|
||||
return m_context;
|
||||
}
|
||||
operator AVCodecContext*(void){
|
||||
return m_context;
|
||||
}
|
||||
operator const AVCodecContext*(void)const{
|
||||
return m_context;
|
||||
}
|
||||
operator bool(void)const{
|
||||
return m_context;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -22,9 +22,18 @@ namespace libav::fmt{
|
||||
reset();
|
||||
}
|
||||
}
|
||||
input_context(const input_context&) = delete;
|
||||
input_context(input_context&& i)noexcept:
|
||||
m_context(std::exchange(i.m_context, nullptr)){}
|
||||
~input_context(void){
|
||||
reset();
|
||||
}
|
||||
|
||||
input_context& operator=(const input_context&) = delete;
|
||||
input_context& operator=(input_context&& i){
|
||||
std::swap(m_context, i.m_context);
|
||||
return *this;
|
||||
}
|
||||
void reset(AVFormatContext* context = nullptr){
|
||||
if(m_context)
|
||||
avformat_close_input(&m_context);
|
||||
@ -65,13 +74,22 @@ namespace libav::fmt{
|
||||
return;
|
||||
if(!(m_context->oformat->flags & AVFMT_NOFILE)){
|
||||
if(avio_open(&m_context->pb, filename, AVIO_FLAG_WRITE) < 0){
|
||||
reset();
|
||||
avformat_free_context(m_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
output_context(const output_context&) = delete;
|
||||
output_context(output_context&& o)noexcept:
|
||||
m_context(std::exchange(o.m_context, nullptr)){}
|
||||
~output_context(void){
|
||||
reset();
|
||||
}
|
||||
|
||||
output_context& operator=(const output_context&) = delete;
|
||||
output_context& operator=(output_context&& o)noexcept{
|
||||
std::swap(m_context, o.m_context);
|
||||
return *this;
|
||||
}
|
||||
void reset(AVFormatContext* context = nullptr){
|
||||
if(m_context){
|
||||
if(!(m_context->oformat->flags & AVFMT_NOFILE)){
|
||||
|
||||
81
include/libav/frame.hpp
Normal file
81
include/libav/frame.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef LIBAV_FRAME_HPP
|
||||
#define LIBAV_FRAME_HPP
|
||||
|
||||
extern "C"{
|
||||
# include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
#include <utility> //exchange
|
||||
|
||||
namespace libav{
|
||||
|
||||
class frame
|
||||
{
|
||||
private:
|
||||
AVFrame* m_frame;
|
||||
bool m_freep = false;
|
||||
public:
|
||||
frame(void){
|
||||
m_frame = av_frame_alloc();
|
||||
m_frame->data[0] = nullptr;
|
||||
}
|
||||
frame(int width, int height, int format):
|
||||
frame()
|
||||
{
|
||||
m_frame->width = width;
|
||||
m_frame->height = height;
|
||||
m_frame->format = format;
|
||||
}
|
||||
frame(const frame&) = delete;
|
||||
frame(frame&& f)noexcept:
|
||||
m_frame(std::exchange(f.m_frame, nullptr)),
|
||||
m_freep(f.m_freep){}
|
||||
~frame(void){
|
||||
reset();
|
||||
}
|
||||
frame& operator=(const frame&) = delete;
|
||||
frame& operator=(frame&& f)noexcept{
|
||||
std::swap(m_frame, f.m_frame);
|
||||
std::swap(m_freep, f.m_freep);
|
||||
return *this;
|
||||
}
|
||||
void reset(AVFrame* frame = nullptr){
|
||||
if(m_frame){
|
||||
if(m_freep){
|
||||
av_freep(&m_frame->data[0]);
|
||||
}
|
||||
av_frame_unref(m_frame);
|
||||
av_frame_free(&m_frame);
|
||||
}
|
||||
m_frame = frame;
|
||||
}
|
||||
void set_freep(bool b = true){
|
||||
m_freep = b;
|
||||
}
|
||||
AVFrame* release(void){
|
||||
return std::exchange(m_frame, nullptr);
|
||||
}
|
||||
|
||||
AVFrame* operator->(void){
|
||||
return m_frame;
|
||||
}
|
||||
const AVFrame* operator->(void)const{
|
||||
return m_frame;
|
||||
}
|
||||
AVFrame* get(void){
|
||||
return m_frame;
|
||||
}
|
||||
const AVFrame* get(void)const{
|
||||
return m_frame;
|
||||
}
|
||||
operator AVFrame*(void){
|
||||
return m_frame;
|
||||
}
|
||||
operator const AVFrame*(void)const{
|
||||
return m_frame;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -13,6 +13,8 @@ extern "C"{
|
||||
#endif
|
||||
|
||||
namespace libav::fmt{}
|
||||
namespace libav::codec{}
|
||||
namespace libavfmt = libav::fmt;
|
||||
namespace libavcodec = libav::codec;
|
||||
|
||||
#endif
|
||||
|
||||
@ -24,9 +24,21 @@ namespace libav{
|
||||
m_pkt->size = 0;
|
||||
}
|
||||
}
|
||||
packet(const packet&) = delete;
|
||||
packet(packet&& p)noexcept:
|
||||
m_pkt(std::exchange(p.m_pkt, nullptr)){}
|
||||
constexpr packet(AVPacket* pkt):
|
||||
m_pkt(pkt){}
|
||||
|
||||
~packet(void){
|
||||
reset();
|
||||
}
|
||||
|
||||
packet& operator=(const packet&) = delete;
|
||||
packet& operator=(packet&& p)noexcept{
|
||||
std::swap(m_pkt, p.m_pkt);
|
||||
return *this;
|
||||
}
|
||||
void reset(AVPacket* packet = nullptr){
|
||||
if(m_pkt)
|
||||
av_packet_free(&m_pkt);
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
/**
|
||||
This file is a part of rexy's matrix bot
|
||||
Copyright (C) 2019 rexy712
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RAII_VIDEO_MAN_HPP
|
||||
#define RAII_VIDEO_MAN_HPP
|
||||
|
||||
#include <memory> //unique_ptr
|
||||
#include "raii/string.hpp"
|
||||
|
||||
//needs to be extern C because quality library writing
|
||||
extern "C"{
|
||||
# include <libavcodec/avcodec.h> //AVCodecContext, AVCodec
|
||||
# include <libavformat/avformat.h> //AVFormatContext
|
||||
# include <libswscale/swscale.h> //sws_scale
|
||||
# include <libavutil/imgutils.h> //av_image_alloc
|
||||
}
|
||||
|
||||
namespace raii{
|
||||
|
||||
class video_man
|
||||
{
|
||||
public:
|
||||
using context_type = std::unique_ptr<AVCodecContext,void(&)(AVCodecContext*)>;
|
||||
using frame_type = std::unique_ptr<AVFrame,void(&)(AVFrame*)>;
|
||||
using packet_type = std::unique_ptr<AVPacket,void(&)(AVPacket*)>;
|
||||
|
||||
private:
|
||||
AVFormatContext* m_vid;
|
||||
AVCodec* m_codec;
|
||||
AVCodecContext* m_context;
|
||||
int m_stream_index = -1;
|
||||
|
||||
|
||||
public:
|
||||
video_man(const raii::string_base& filename);
|
||||
video_man(const video_man& v) = delete;
|
||||
video_man(video_man&& v);
|
||||
~video_man(void);
|
||||
|
||||
int height(void)const;
|
||||
int width(void)const;
|
||||
raii::string get_filetype(void)const;
|
||||
raii::string get_mimetype(void)const;
|
||||
packet_type create_jpg_thumbnail(void);
|
||||
|
||||
AVFormatContext* release(void);
|
||||
void reset(const raii::string_base& filename);
|
||||
void reset(void);
|
||||
|
||||
operator bool(void)const;
|
||||
private:
|
||||
void _init(const raii::string_base& filename);
|
||||
AVFormatContext* _open_video_file(const raii::string_base& filename);
|
||||
static AVFrame* _init_frame(int w, int h, int format);
|
||||
static void _change_color_range(SwsContext* sws_ctx);
|
||||
static context_type _get_jpeg_context(const AVCodecContext* decoder);
|
||||
static void _context_deleter(AVCodecContext* ptr);
|
||||
static void _frame_deleter(AVFrame* ptr);
|
||||
static void _packet_deleter(AVPacket* ptr);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
113
src/matrix.cpp
113
src/matrix.cpp
@ -25,7 +25,16 @@
|
||||
#include "raii/rjp_ptr.hpp"
|
||||
#include "raii/filerd.hpp"
|
||||
#include "fat_strings.hpp"
|
||||
#include "raii/video_man.hpp"
|
||||
|
||||
#include "libav/frame.hpp"
|
||||
#include "libav/codec/context.hpp"
|
||||
#include "libav/fmt/context.hpp"
|
||||
#include "libav/packet.hpp"
|
||||
|
||||
extern "C"{
|
||||
# include <libswscale/swscale.h> //sws_scale
|
||||
# include <libavutil/imgutils.h> //av_image_alloc
|
||||
}
|
||||
|
||||
namespace matrix{
|
||||
|
||||
@ -221,23 +230,98 @@ namespace matrix{
|
||||
return upload_audio(filename, raii::static_string());
|
||||
}
|
||||
#ifdef HAS_FFMPEG
|
||||
libavcodec::context _get_jpeg_context(const AVCodecContext* src){
|
||||
AVCodec* jpg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
|
||||
libavcodec::context jctx(jpg_codec);
|
||||
jctx->pix_fmt = AV_PIX_FMT_YUVJ420P;
|
||||
jctx->width = src->width;
|
||||
jctx->height = src->height;
|
||||
jctx->codec_id = AV_CODEC_ID_MJPEG;
|
||||
jctx->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
if(src->time_base.num == 0 || src->time_base.den == 0)
|
||||
jctx->time_base = AVRational{1, 30};
|
||||
else
|
||||
jctx->time_base = src->time_base;
|
||||
jctx.open();
|
||||
return jctx;
|
||||
}
|
||||
void _change_color_range(SwsContext* sws_ctx){
|
||||
int dummy[4];
|
||||
int src_range, dest_range;
|
||||
int br, con, sat;
|
||||
sws_getColorspaceDetails(sws_ctx, (int**)&dummy, &src_range, (int**)&dummy, &dest_range, &br, &con, &sat);
|
||||
const int* coefs = sws_getCoefficients(SWS_CS_DEFAULT);
|
||||
src_range = 2;
|
||||
sws_setColorspaceDetails(sws_ctx, coefs, src_range, coefs, dest_range, br, con, sat);
|
||||
}
|
||||
libav::packet create_jpeg_thumbnail(libavfmt::input_context& src, libavcodec::context& src_ctx, int index){
|
||||
libavcodec::context jpg_context = _get_jpeg_context(src_ctx);
|
||||
libav::frame src_frame(src_ctx->width, src_ctx->height, src_ctx->pix_fmt);
|
||||
libav::frame jpg_frame(src_ctx->width, src_ctx->height, jpg_context->pix_fmt);
|
||||
|
||||
libav::packet packet;
|
||||
SwsContext* sws_ctx = sws_getContext(src_ctx->width, src_ctx->height, src_ctx->pix_fmt,
|
||||
src_ctx->width, src_ctx->height, AV_PIX_FMT_YUV420P,
|
||||
SWS_BILINEAR, NULL, NULL, NULL);
|
||||
_change_color_range(sws_ctx);
|
||||
|
||||
av_image_alloc(jpg_frame->data, jpg_frame->linesize, src_ctx->width, src_ctx->height, jpg_context->pix_fmt, 32);
|
||||
jpg_frame.set_freep();
|
||||
while(av_read_frame(src, packet) >= 0){
|
||||
if(packet->stream_index == index){
|
||||
avcodec_send_packet(src_ctx, packet);
|
||||
if(avcodec_receive_frame(src_ctx, src_frame) >= 0)
|
||||
break;
|
||||
}
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
sws_scale(sws_ctx, src_frame->data, src_frame->linesize, 0, src_ctx->height, jpg_frame->data, jpg_frame->linesize);
|
||||
|
||||
sws_freeContext(sws_ctx);
|
||||
|
||||
if(avcodec_send_frame(jpg_context, jpg_frame) < 0){
|
||||
return libav::packet(nullptr);
|
||||
}
|
||||
if(avcodec_receive_packet(jpg_context, packet) < 0){
|
||||
return libav::packet(nullptr);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
raii::string get_mimetype(const libav::fmt::input_context& ctx){
|
||||
const char* first = strstr(ctx->iformat->name, ",");
|
||||
if(first)
|
||||
return raii::string("video/" + raii::static_string(ctx->iformat->name, first - ctx->iformat->name));
|
||||
return raii::string("video/" + raii::static_string(ctx->iformat->name));
|
||||
}
|
||||
video_info bot::upload_video(const raii::string_base& filename, const raii::string_base& alias){
|
||||
video_info ret = {};
|
||||
|
||||
raii::video_man context(filename);
|
||||
if(!context)
|
||||
libav::fmt::input_context in(filename);
|
||||
int stream_index = -1;
|
||||
for(size_t i = 0;i < in->nb_streams;++i){
|
||||
if(in->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
|
||||
stream_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(stream_index == -1)
|
||||
return {};
|
||||
auto packet = context.create_jpg_thumbnail();
|
||||
|
||||
libavcodec::context src_ctx(in, stream_index);
|
||||
src_ctx.open();
|
||||
libav::packet packet = create_jpeg_thumbnail(in, src_ctx, stream_index);
|
||||
|
||||
raii::curl_llist header("Content-Type: image/jpeg");
|
||||
|
||||
ret.thumb_width = context.width();
|
||||
ret.thumb_height = context.height();
|
||||
ret.width = context.width();
|
||||
ret.height = context.height();
|
||||
ret.mimetype = context.get_mimetype();
|
||||
context.reset(); //early cleanup to save memory
|
||||
ret.thumb_width = src_ctx->width;
|
||||
ret.thumb_height = src_ctx->height;
|
||||
ret.width = src_ctx->width;
|
||||
ret.height = src_ctx->height;
|
||||
ret.mimetype = get_mimetype(in);
|
||||
ret.thumbsize = packet->size;
|
||||
ret.thumburl = _post_and_find(raii::static_string((char*)packet->data, packet->size), m_urls.file_upload, header, "content_uri"_ss);
|
||||
src_ctx.reset();
|
||||
in.reset();
|
||||
packet.reset();
|
||||
|
||||
header = raii::curl_llist(raii::string("Content-Type:" + ret.mimetype));
|
||||
@ -251,11 +335,10 @@ namespace matrix{
|
||||
audio_info bot::upload_audio(const raii::string_base& filename, const raii::string_base& alias){
|
||||
audio_info ret = {};
|
||||
|
||||
raii::video_man context(filename);
|
||||
if(!context)
|
||||
return {};
|
||||
ret.mimetype = context.get_mimetype();
|
||||
context.reset();
|
||||
libav::fmt::input_context in(filename);
|
||||
|
||||
ret.mimetype = get_mimetype(in);
|
||||
in.reset();
|
||||
raii::curl_llist header(raii::string("Content-Type:" + ret.mimetype));
|
||||
raii::filerd fd(filename);
|
||||
if(!fd) return {};
|
||||
|
||||
@ -1,193 +0,0 @@
|
||||
/**
|
||||
This file is a part of rexy's matrix bot
|
||||
Copyright (C) 2019 rexy712
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "raii/video_man.hpp"
|
||||
#include "raii/static_string.hpp"
|
||||
|
||||
#include <utility> //exchange
|
||||
|
||||
//av_register_all is required before ffmpeg 4.0 and is deprecated after that
|
||||
#if LIBAVFORMAT_VERSION_MAJOR >= 58 && LIBAVFORMAT_VERSION_MINOR >= 7
|
||||
# define REGISTER_LIBAV()
|
||||
#else
|
||||
# define REGISTER_LIBAV() av_register_all()
|
||||
#endif
|
||||
|
||||
namespace raii{
|
||||
|
||||
video_man::video_man(const raii::string_base& filename){
|
||||
REGISTER_LIBAV();
|
||||
_init(filename);
|
||||
}
|
||||
video_man::video_man(video_man&& v):
|
||||
m_vid(std::exchange(v.m_vid, nullptr)){}
|
||||
video_man::~video_man(void){
|
||||
reset();
|
||||
}
|
||||
|
||||
int video_man::height(void)const{
|
||||
return m_context->height;
|
||||
}
|
||||
int video_man::width(void)const{
|
||||
return m_context->width;
|
||||
}
|
||||
raii::string video_man::get_filetype(void)const{
|
||||
const char* first = strstr(m_vid->iformat->name, ",");
|
||||
if(first)
|
||||
return raii::string(raii::static_string(m_vid->iformat->name, first - m_vid->iformat->name));
|
||||
return raii::string(raii::static_string(m_vid->iformat->name));
|
||||
}
|
||||
raii::string video_man::get_mimetype(void)const{
|
||||
const char* first = strstr(m_vid->iformat->name, ",");
|
||||
if(first)
|
||||
return raii::string("video/" + raii::static_string(m_vid->iformat->name, first - m_vid->iformat->name));
|
||||
return raii::string("video/" + raii::static_string(m_vid->iformat->name));
|
||||
}
|
||||
auto video_man::create_jpg_thumbnail(void) -> packet_type{
|
||||
context_type jpg_context = _get_jpeg_context(m_context);
|
||||
frame_type frame(_init_frame(m_context->width, m_context->height, m_context->pix_fmt), _frame_deleter);
|
||||
frame_type jpg_frame(_init_frame(m_context->width, m_context->height, jpg_context->pix_fmt), _frame_deleter);
|
||||
packet_type packet(av_packet_alloc(), _packet_deleter);
|
||||
SwsContext* sws_ctx = sws_getContext(m_context->width, m_context->height, m_context->pix_fmt,
|
||||
m_context->width, m_context->height, AV_PIX_FMT_YUV420P,
|
||||
SWS_BILINEAR, NULL, NULL, NULL);
|
||||
_change_color_range(sws_ctx);
|
||||
|
||||
av_image_alloc(jpg_frame->data, jpg_frame->linesize, m_context->width, m_context->height, jpg_context->pix_fmt, 32);
|
||||
while(av_read_frame(m_vid, packet.get()) >= 0){
|
||||
if(packet->stream_index == m_stream_index){
|
||||
avcodec_send_packet(m_context, packet.get());
|
||||
if(avcodec_receive_frame(m_context, frame.get()) >= 0)
|
||||
break;
|
||||
}
|
||||
av_packet_unref(packet.get());
|
||||
}
|
||||
sws_scale(sws_ctx, frame->data, frame->linesize, 0, m_context->height, jpg_frame->data, jpg_frame->linesize);
|
||||
|
||||
sws_freeContext(sws_ctx);
|
||||
|
||||
packet_type jpg_packet(av_packet_alloc(), _packet_deleter);
|
||||
if(avcodec_send_frame(jpg_context.get(), jpg_frame.get()) < 0){
|
||||
av_freep(&jpg_frame->data[0]);
|
||||
return packet_type(nullptr, _packet_deleter);
|
||||
}
|
||||
if(avcodec_receive_packet(jpg_context.get(), jpg_packet.get()) < 0){
|
||||
return packet_type(nullptr, _packet_deleter);
|
||||
}
|
||||
|
||||
av_freep(&jpg_frame->data[0]);
|
||||
return jpg_packet;
|
||||
}
|
||||
|
||||
AVFormatContext* video_man::release(void){
|
||||
avcodec_close(m_context);
|
||||
avcodec_free_context(&m_context);
|
||||
m_context = nullptr;
|
||||
m_codec = nullptr;
|
||||
m_stream_index = -1;
|
||||
return std::exchange(m_vid, nullptr);
|
||||
}
|
||||
void video_man::reset(const raii::string_base& filename){
|
||||
reset();
|
||||
_init(filename);
|
||||
}
|
||||
void video_man::reset(void){
|
||||
avcodec_close(m_context);
|
||||
avcodec_free_context(&m_context);
|
||||
avformat_close_input(&m_vid);
|
||||
m_context = nullptr;
|
||||
m_vid = nullptr;
|
||||
m_codec = nullptr;
|
||||
m_stream_index = -1;
|
||||
}
|
||||
video_man::operator bool(void)const{
|
||||
return m_vid;
|
||||
}
|
||||
void video_man::_init(const raii::string_base& filename){
|
||||
m_vid = _open_video_file(filename);
|
||||
if(!m_vid)
|
||||
return;
|
||||
|
||||
AVCodecParameters* codec_parms = m_vid->streams[m_stream_index]->codecpar;
|
||||
m_codec = avcodec_find_decoder(codec_parms->codec_id);
|
||||
m_context = avcodec_alloc_context3(m_codec);
|
||||
avcodec_parameters_to_context(m_context, codec_parms);
|
||||
avcodec_open2(m_context, m_codec, NULL);
|
||||
}
|
||||
AVFormatContext* video_man::_open_video_file(const raii::string_base& filename){
|
||||
AVFormatContext* context = NULL;
|
||||
avformat_open_input(&context, filename.get(), NULL, NULL);
|
||||
avformat_find_stream_info(context, NULL);
|
||||
for(size_t i = 0;i < context->nb_streams;++i){
|
||||
if(context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
|
||||
m_stream_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(m_stream_index != -1)
|
||||
return context;
|
||||
avformat_close_input(&context);
|
||||
return nullptr;
|
||||
}
|
||||
AVFrame* video_man::_init_frame(int w, int h, int format){
|
||||
AVFrame* f = av_frame_alloc();
|
||||
f->data[0] = NULL;
|
||||
f->width = w;
|
||||
f->height = h;
|
||||
f->format = format;
|
||||
return f;
|
||||
}
|
||||
void video_man::_change_color_range(SwsContext* sws_ctx){
|
||||
//we want to convert from YUVJ420P to YUV420P for sws_scale to be happy. but we actually want to output as YUVJ420P.
|
||||
//so we change the color range to use the full range like YUVJ420P. dummy is used to ignore unneeded returns.
|
||||
int dummy[4];
|
||||
int src_range, dest_range;
|
||||
int br, con, sat;
|
||||
sws_getColorspaceDetails(sws_ctx, (int**)&dummy, &src_range, (int**)&dummy, &dest_range, &br, &con, &sat);
|
||||
const int* coefs = sws_getCoefficients(SWS_CS_DEFAULT);
|
||||
src_range = 2;
|
||||
sws_setColorspaceDetails(sws_ctx, coefs, src_range, coefs, dest_range, br, con, sat);
|
||||
}
|
||||
auto video_man::_get_jpeg_context(const AVCodecContext* decoder) -> context_type{
|
||||
AVCodec* jpg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
|
||||
context_type jpg_context(avcodec_alloc_context3(jpg_codec), _context_deleter);
|
||||
jpg_context->pix_fmt = AV_PIX_FMT_YUVJ420P;
|
||||
jpg_context->width = decoder->width;
|
||||
jpg_context->height = decoder->height;
|
||||
jpg_context->codec_id = AV_CODEC_ID_MJPEG;
|
||||
jpg_context->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
if(decoder->time_base.num == 0 || decoder->time_base.den == 0)
|
||||
jpg_context->time_base = AVRational{1, 30};
|
||||
else
|
||||
jpg_context->time_base = decoder->time_base;
|
||||
avcodec_open2(jpg_context.get(), jpg_codec, NULL);
|
||||
return jpg_context;
|
||||
}
|
||||
void video_man::_context_deleter(AVCodecContext* ptr){
|
||||
avcodec_close(ptr);
|
||||
avcodec_free_context(&ptr);
|
||||
}
|
||||
void video_man::_frame_deleter(AVFrame* ptr){
|
||||
av_frame_unref(ptr);
|
||||
av_frame_free(&ptr);
|
||||
}
|
||||
void video_man::_packet_deleter(AVPacket* ptr){
|
||||
av_packet_unref(ptr);
|
||||
av_packet_free(&ptr);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user