You've already forked M5Stack_Linux_Libs
mirror of
https://github.com/m5stack/M5Stack_Linux_Libs.git
synced 2026-05-20 11:01:38 -07:00
719 lines
22 KiB
C++
719 lines
22 KiB
C++
/*
|
||
* @Copyright: iflytek
|
||
* @Autor: zghong
|
||
* @Date: 2020-04-07 12:18:54
|
||
* @Description: 利用FFmpeg,对常见的编码格式文件进行编解码
|
||
*
|
||
* 编解码封装在vcodec类中,接口为encode()和decode()函数。
|
||
* 使用时需要指出<源文件>,<目标文件>及<编解码器名>。其中编解码器名可以通过`ffmpeg -encoders, ffmpeg -decoders`查看。
|
||
*/
|
||
|
||
#ifndef _VCODEC_HPP
|
||
#define _VCODEC_HPP
|
||
|
||
#include <string>
|
||
#include <streambuf>
|
||
#include <fstream>
|
||
#ifdef __cplusplus
|
||
extern "C"
|
||
{
|
||
#endif
|
||
|
||
#include "libavcodec/avcodec.h"
|
||
#include "libavutil/opt.h"
|
||
#include "libavutil/imgutils.h"
|
||
#include "libswscale/swscale.h"
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
/**********************************************************************
|
||
* vcodec类定义部分
|
||
*
|
||
* 进行视频编解码类,实例化时需要指出<源文件>,<目标文件>及<编解码器名>
|
||
* 对外的接口如下:
|
||
* 1、encode(),编码
|
||
* 2、decode(),解码
|
||
**********************************************************************
|
||
*/
|
||
class vcodec
|
||
{
|
||
public:
|
||
enum
|
||
{
|
||
FILE_READ_CALL,
|
||
FILE_READ_WRITE,
|
||
FILE_READ_WRITE_CALL,
|
||
IOSTREAM_READ_CALL,
|
||
IOSTREAM_READ_WRITE,
|
||
IOSTREAM_READ_WRITE_CALL,
|
||
CUSTOM_READ_CALL,
|
||
CUSTOM_READ_WRITE,
|
||
CUSTOM_READ_WRITE_CALL,
|
||
};
|
||
typedef void (*callback_get_ones_frame_t)(size_t, void *, size_t);
|
||
typedef int (*callback_inface_fun_t)(void *, size_t);
|
||
typedef struct _frame_rgb_data
|
||
{
|
||
char *data;
|
||
size_t len;
|
||
size_t h;
|
||
size_t w;
|
||
} frame_rgb_data_t;
|
||
frame_rgb_data_t rgb;
|
||
vcodec(std::string in_path, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
vcodec(std::string in_path, std::string out_path, std::string _codec_name);
|
||
vcodec(std::string in_path, std::string out_path, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
vcodec(std::iostream *sin, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
vcodec(std::iostream *sin, std::iostream *sout, std::string _codec_name);
|
||
vcodec(std::iostream *sin, std::iostream *sout, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
vcodec(callback_inface_fun_t read, callback_inface_fun_t eof, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
vcodec(callback_inface_fun_t read, callback_inface_fun_t eof, callback_inface_fun_t write, std::string _codec_name);
|
||
vcodec(callback_inface_fun_t read, callback_inface_fun_t eof, callback_inface_fun_t write, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
|
||
void set_callback(callback_get_ones_frame_t callback);
|
||
|
||
callback_inface_fun_t custom_write, custom_read, custom_eof;
|
||
|
||
int yuv2rgb(void *_frame, int mode);
|
||
int yuv2rgb(void *_frame);
|
||
void data_init(callback_inface_fun_t read, callback_inface_fun_t eof, callback_inface_fun_t write, std::string in_path, std::string out_path, std::iostream *sin, std::iostream *sout, std::string _codec_name, callback_get_ones_frame_t callback);
|
||
void clear(void);
|
||
~vcodec();
|
||
int encode();
|
||
int decode();
|
||
|
||
private:
|
||
int mode;
|
||
std::fstream fin;
|
||
std::fstream fout;
|
||
int use_file;
|
||
std::iostream *_in;
|
||
std::iostream *_out;
|
||
std::string codec_name;
|
||
|
||
AVPicture g_oPicture = {0};
|
||
struct SwsContext *g_pScxt = NULL;
|
||
|
||
AVFrame *frame;
|
||
AVPacket *packet;
|
||
AVCodec *codec;
|
||
AVCodecContext *codec_ctx;
|
||
AVCodecParserContext *parser_ctx;
|
||
callback_get_ones_frame_t fun;
|
||
int encode_frame2packet();
|
||
int decode_packet2frame();
|
||
int c_write(void *buf, size_t n);
|
||
int c_read(void *buf, size_t n);
|
||
int c_eof(void *buf, size_t n);
|
||
};
|
||
|
||
/**********************************************************************
|
||
* vcodec类实现部分
|
||
**********************************************************************
|
||
*/
|
||
void vcodec::data_init(callback_inface_fun_t read, callback_inface_fun_t eof, callback_inface_fun_t write, std::string in_path, std::string out_path, std::iostream *sin, std::iostream *sout, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
this->custom_read = read;
|
||
this->custom_eof = eof;
|
||
this->custom_write = write;
|
||
this->rgb.data = NULL;
|
||
this->_in = sin;
|
||
this->_out = sout;
|
||
this->fun = callback;
|
||
this->use_file = 0;
|
||
this->codec_name = _codec_name;
|
||
if (in_path.length() != 0)
|
||
{
|
||
this->fin.open(in_path.c_str(), std::ios::binary | std::ios::in);
|
||
if (!this->fin.is_open())
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to open <%s>\n", in_path.c_str());
|
||
this->fin.close();
|
||
exit(-1);
|
||
}
|
||
this->_in = &this->fin;
|
||
this->use_file = 1;
|
||
}
|
||
if (out_path.length() != 0)
|
||
{
|
||
this->fout.open(out_path.c_str(), std::ios::binary | std::ios::out | std::ios::trunc);
|
||
if (!this->fout.is_open())
|
||
{
|
||
this->fin.close();
|
||
this->fout.close();
|
||
fprintf(stderr, "[ERROR] Failed to open <%s>\n", out_path.c_str());
|
||
exit(-1);
|
||
}
|
||
this->_out = &this->fout;
|
||
this->use_file = 2;
|
||
}
|
||
}
|
||
vcodec::vcodec(std::string in_path, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
std::string __in_path = in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = NULL;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = callback;
|
||
data_init(NULL, NULL, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = FILE_READ_CALL;
|
||
}
|
||
|
||
/**
|
||
* @brief: vcodec类构造函数
|
||
* @param in_path 输入文件路径
|
||
* @param out_path 输出文件路径
|
||
* @param codec_name 编解码器名
|
||
*/
|
||
vcodec::vcodec(std::string in_path, std::string out_path, std::string _codec_name)
|
||
{
|
||
std::string __in_path = in_path;
|
||
std::string __out_path = out_path;
|
||
std::iostream *__sin = NULL;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = NULL;
|
||
data_init(NULL, NULL, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = FILE_READ_WRITE;
|
||
}
|
||
vcodec::vcodec(std::string in_path, std::string out_path, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
std::string __in_path = in_path;
|
||
std::string __out_path = out_path;
|
||
std::iostream *__sin = NULL;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = callback;
|
||
data_init(NULL, NULL, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = FILE_READ_WRITE_CALL;
|
||
}
|
||
vcodec::vcodec(std::iostream *sin, std::iostream *sout, std::string _codec_name)
|
||
{
|
||
std::string __in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = sin;
|
||
std::iostream *__sout = sout;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = NULL;
|
||
data_init(NULL, NULL, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = IOSTREAM_READ_WRITE;
|
||
}
|
||
vcodec::vcodec(std::iostream *sin, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
std::string __in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = sin;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = callback;
|
||
data_init(NULL, NULL, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = IOSTREAM_READ_CALL;
|
||
}
|
||
vcodec::vcodec(std::iostream *sin, std::iostream *sout, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
std::string __in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = sin;
|
||
std::iostream *__sout = sout;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = callback;
|
||
data_init(NULL, NULL, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = IOSTREAM_READ_WRITE_CALL;
|
||
}
|
||
|
||
vcodec::vcodec(callback_inface_fun_t read, callback_inface_fun_t eof, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
std::string __in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = NULL;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = callback;
|
||
data_init(read, eof, NULL, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = CUSTOM_READ_CALL;
|
||
}
|
||
vcodec::vcodec(callback_inface_fun_t read, callback_inface_fun_t eof, callback_inface_fun_t write, std::string _codec_name)
|
||
{
|
||
std::string __in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = NULL;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = NULL;
|
||
data_init(read, eof, write, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = CUSTOM_READ_WRITE;
|
||
}
|
||
vcodec::vcodec(callback_inface_fun_t read, callback_inface_fun_t eof, callback_inface_fun_t write, std::string _codec_name, callback_get_ones_frame_t callback)
|
||
{
|
||
std::string __in_path;
|
||
std::string __out_path;
|
||
std::iostream *__sin = NULL;
|
||
std::iostream *__sout = NULL;
|
||
std::string __codec_name = _codec_name;
|
||
callback_get_ones_frame_t __callback = callback;
|
||
data_init(read, eof, write, __in_path, __out_path, __sin, __sout, __codec_name, __callback);
|
||
this->mode = CUSTOM_READ_WRITE_CALL;
|
||
}
|
||
|
||
void vcodec::set_callback(callback_get_ones_frame_t callback)
|
||
{
|
||
this->fun = callback;
|
||
}
|
||
|
||
int vcodec::yuv2rgb(void *_frame, int mode)
|
||
{
|
||
AVFrame *pFrame = (AVFrame *)_frame;
|
||
int width = pFrame->width;
|
||
int height = pFrame->height;
|
||
|
||
if (g_pScxt == NULL)
|
||
{
|
||
g_pScxt = sws_getContext(width, height, (AVPixelFormat)pFrame->format,
|
||
width, height, (AVPixelFormat)mode,
|
||
NULL, NULL, NULL, NULL);
|
||
// AVFrame需要填充,还是这个方便。
|
||
avpicture_alloc(&g_oPicture, (AVPixelFormat)mode, width, height);
|
||
}
|
||
int num_bytes = av_image_get_buffer_size((AVPixelFormat)mode, width, height, 32);
|
||
int retsws = sws_scale(g_pScxt, pFrame->data, pFrame->linesize, 0, height,
|
||
g_oPicture.data, g_oPicture.linesize);
|
||
// //注意,RGB数据是这样复制的
|
||
if (this->rgb.data == NULL)
|
||
{
|
||
this->rgb.data = (char *)malloc(num_bytes);
|
||
}
|
||
if (rgb.len != num_bytes)
|
||
{
|
||
free(this->rgb.data);
|
||
this->rgb.data = (char *)malloc(num_bytes);
|
||
}
|
||
memcpy(this->rgb.data, g_oPicture.data[0], num_bytes);
|
||
rgb.w = width;
|
||
rgb.h = height;
|
||
rgb.len = num_bytes;
|
||
return 0;
|
||
}
|
||
|
||
int vcodec::yuv2rgb(void *_frame)
|
||
{
|
||
return yuv2rgb(_frame, AV_PIX_FMT_RGB24);
|
||
}
|
||
|
||
void vcodec::clear(void)
|
||
{
|
||
switch (this->use_file)
|
||
{
|
||
case 2:
|
||
this->fout.close();
|
||
case 1:
|
||
this->fin.close();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
if (this->g_pScxt != NULL)
|
||
{
|
||
avpicture_free(&this->g_oPicture);
|
||
this->g_oPicture = {0};
|
||
sws_freeContext(this->g_pScxt);
|
||
this->g_pScxt = NULL;
|
||
free(this->rgb.data);
|
||
this->rgb.data = NULL;
|
||
}
|
||
}
|
||
/**
|
||
* @brief: vcodec类析构函数
|
||
*/
|
||
vcodec::~vcodec()
|
||
{
|
||
clear();
|
||
}
|
||
|
||
/**
|
||
* @brief: 使用给定的编解码器对输入文件编码,将结果写入输出文件
|
||
* @return: 0 for ok, -1 for error
|
||
*/
|
||
int vcodec::encode()
|
||
{
|
||
// allocation
|
||
this->frame = av_frame_alloc();
|
||
if (!this->frame)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to allocate frame\n");
|
||
return -1;
|
||
}
|
||
this->packet = av_packet_alloc();
|
||
if (!this->packet)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to allocate packet\n");
|
||
return -1;
|
||
}
|
||
|
||
this->codec = avcodec_find_encoder_by_name(this->codec_name.c_str());
|
||
if (!this->codec)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to find codec\n");
|
||
return -1;
|
||
}
|
||
this->codec_ctx = avcodec_alloc_context3(this->codec);
|
||
if (!this->codec_ctx)
|
||
{
|
||
fprintf(stderr, "[ERROR] Faild to allocate codec context\n");
|
||
return -1;
|
||
}
|
||
|
||
// encoder settings
|
||
this->codec_ctx->codec_id = this->codec->id;
|
||
this->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
|
||
this->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
|
||
this->codec_ctx->width = 640;
|
||
this->codec_ctx->height = 480;
|
||
this->codec_ctx->time_base = (AVRational){1, 30}; // fps
|
||
// vbr设置
|
||
// int64_t br = 468000;
|
||
// this->codec_ctx->bit_rate = br;
|
||
// this->codec_ctx->rc_min_rate = br;
|
||
// this->codec_ctx->rc_max_rate = br;
|
||
// this->codec_ctx->bit_rate_tolerance = br;
|
||
// this->codec_ctx->rc_buffer_size = br;
|
||
// this->codec_ctx->rc_initial_buffer_occupancy = this->codec_ctx->rc_buffer_size * 3 / 4;
|
||
this->codec_ctx->bit_rate = 468000;
|
||
this->codec_ctx->gop_size = 250;
|
||
this->codec_ctx->max_b_frames = 0; // no b-frame
|
||
if (this->codec_ctx->codec_id == AV_CODEC_ID_H264)
|
||
{
|
||
av_opt_set(this->codec_ctx->priv_data, "preset", "slow", 0);
|
||
av_opt_set(this->codec_ctx->priv_data, "tune", "zerolatency", 0);
|
||
}
|
||
else if (this->codec_ctx->codec_id == AV_CODEC_ID_H265)
|
||
{
|
||
av_opt_set(this->codec_ctx->priv_data, "preset", "ultrafast", 0);
|
||
av_opt_set(this->codec_ctx->priv_data, "tune", "zero-latency", 0);
|
||
}
|
||
|
||
this->frame->format = this->codec_ctx->pix_fmt;
|
||
this->frame->width = this->codec_ctx->width;
|
||
this->frame->height = this->codec_ctx->height;
|
||
|
||
// open the codec
|
||
if (avcodec_open2(this->codec_ctx, this->codec, NULL) < 0)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to open codec\n");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
fprintf(stdout, "[INFO] Open codec successfully\n");
|
||
}
|
||
|
||
// encode 1 second of video
|
||
int frame_size = av_image_get_buffer_size(this->codec_ctx->pix_fmt, this->codec_ctx->width, this->codec_ctx->height, 1);
|
||
uint8_t *frame_buf = (uint8_t *)av_malloc(frame_size);
|
||
int y_size = this->codec_ctx->width * this->codec_ctx->height; // size of Y
|
||
av_image_fill_arrays(this->frame->data, this->frame->linesize, frame_buf, this->codec_ctx->pix_fmt, this->codec_ctx->width, this->codec_ctx->height, 1);
|
||
int i = 0;
|
||
while (!this->c_eof(NULL, 0))
|
||
{
|
||
int num = this->c_read(frame_buf, (y_size * 3 / 2));
|
||
if (num < 0)
|
||
{
|
||
break;
|
||
}
|
||
else if (num == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// read yuv data from source file into AVFrame
|
||
this->frame->data[0] = frame_buf; // Y
|
||
this->frame->data[1] = frame_buf + y_size; // U
|
||
this->frame->data[2] = frame_buf + y_size * 5 / 4; // V
|
||
this->frame->pts = i++;
|
||
|
||
// encode frame into packet
|
||
if (this->encode_frame2packet() != 0)
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
// flush the encoder
|
||
this->frame = NULL;
|
||
this->encode_frame2packet();
|
||
|
||
av_frame_free(&this->frame);
|
||
av_packet_free(&this->packet);
|
||
avcodec_free_context(&this->codec_ctx);
|
||
|
||
fprintf(stdout, "[SUCCESS] Encode file successfully\n");
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief: 使用给定的编解码器对输入文件解码,将结果写入输出文件
|
||
* @return: 0 for ok, -1 for error
|
||
*/
|
||
int vcodec::decode()
|
||
{
|
||
// allocation
|
||
this->frame = av_frame_alloc();
|
||
if (!this->frame)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to allocate frame\n");
|
||
return -1;
|
||
}
|
||
this->packet = av_packet_alloc();
|
||
if (!this->packet)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to allocate packet\n");
|
||
return -1;
|
||
}
|
||
this->codec = avcodec_find_decoder_by_name(this->codec_name.c_str());
|
||
if (!this->codec)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to find codec\n");
|
||
return -1;
|
||
}
|
||
this->codec_ctx = avcodec_alloc_context3(this->codec);
|
||
if (!this->codec_ctx)
|
||
{
|
||
fprintf(stderr, "[ERROR] Faild to allocate codec context\n");
|
||
return -1;
|
||
}
|
||
this->parser_ctx = av_parser_init(this->codec->id);
|
||
if (!this->parser_ctx)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to find parser of codec\n");
|
||
return -1;
|
||
}
|
||
|
||
// open the codec
|
||
if (avcodec_open2(this->codec_ctx, this->codec, NULL) < 0)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to open codec\n");
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
fprintf(stdout, "[INFO] Open codec successfully\n");
|
||
}
|
||
|
||
// start to decode
|
||
int input_buf_size = 4096;
|
||
uint8_t input_buf[input_buf_size + AV_INPUT_BUFFER_PADDING_SIZE] = {0};
|
||
while (!this->c_eof(NULL, 0))
|
||
{
|
||
// read source data
|
||
// this->_in->read((char *)input_buf, input_buf_size);
|
||
// int read_size = this->_in->gcount();
|
||
int read_size = this->c_read(input_buf, input_buf_size);
|
||
if (read_size < 0)
|
||
{
|
||
break;
|
||
}
|
||
else if (read_size == 0)
|
||
{
|
||
continue;
|
||
}
|
||
uint8_t *input_buf_pos = input_buf;
|
||
while (read_size > 0)
|
||
{
|
||
// parse data into packet
|
||
int parsed_size = av_parser_parse2(this->parser_ctx, this->codec_ctx,
|
||
&this->packet->data, &this->packet->size, input_buf_pos, read_size,
|
||
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||
if (parsed_size < 0)
|
||
{
|
||
fprintf(stderr, "Error while parsing\n");
|
||
return -1;
|
||
}
|
||
// update position of buffer and size of remained data
|
||
input_buf_pos += parsed_size;
|
||
read_size -= parsed_size;
|
||
|
||
if (this->packet->size)
|
||
{
|
||
// decode packet into frame
|
||
if (this->decode_packet2frame() != 0)
|
||
{
|
||
fprintf(stderr, "Error while packet2frame\n");
|
||
return -1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
fprintf(stdout, "[SUCCESS] Decode file successfully\n");
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief: 将数据帧编码成数据包
|
||
* @return: 0 for ok, -1 for error
|
||
*/
|
||
int vcodec::encode_frame2packet()
|
||
{
|
||
int ret = avcodec_send_frame(this->codec_ctx, this->frame);
|
||
if (ret < 0)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to send a frame for encoding\n");
|
||
return -1;
|
||
}
|
||
while (ret >= 0)
|
||
{
|
||
ret = avcodec_receive_packet(this->codec_ctx, this->packet);
|
||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||
{
|
||
return 0;
|
||
}
|
||
else if (ret < 0)
|
||
{
|
||
fprintf(stderr, "[ERROR] Error during encoding, code <%d>\n", ret);
|
||
return -1;
|
||
}
|
||
static size_t ecount = 0;
|
||
if (this->fun)
|
||
this->fun(ecount++, this->packet->data, this->packet->size);
|
||
if (this->_out)
|
||
this->c_write((this->packet->data), (this->packet->size));
|
||
// this->_out->write((char *)this->packet->data, this->packet->size);
|
||
fprintf(stdout, "[INFO] Saving packet %3" PRId64 " (size=%5d)\n", this->packet->pts, this->packet->size);
|
||
av_packet_unref(this->packet);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief: 将数据包解码成数据帧
|
||
* @return: 0 for ok, -1 for error
|
||
*/
|
||
int vcodec::decode_packet2frame()
|
||
{
|
||
int ret = avcodec_send_packet(this->codec_ctx, this->packet);
|
||
if (ret < 0)
|
||
{
|
||
fprintf(stderr, "[ERROR] Failed to send a packet for decoding\n");
|
||
return -1;
|
||
}
|
||
while (ret >= 0)
|
||
{
|
||
ret = avcodec_receive_frame(this->codec_ctx, frame);
|
||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||
{
|
||
return 0;
|
||
}
|
||
else if (ret < 0)
|
||
{
|
||
fprintf(stderr, "[ERROR] Error during decoding, code <%d>\n", ret);
|
||
return -1;
|
||
}
|
||
static size_t dcount = 0;
|
||
if (this->fun)
|
||
this->fun(dcount++, frame, 0);
|
||
// save the frame into file
|
||
// Y, U, V
|
||
if (this->_out)
|
||
{
|
||
|
||
for (int i = 0; i < frame->height; i++)
|
||
{
|
||
// this->_out->write((char *)(frame->data[0] + frame->linesize[0] * i), frame->width);
|
||
this->c_write((frame->data[0] + frame->linesize[0] * i), (frame->width));
|
||
}
|
||
for (int i = 0; i < frame->height / 2; i++)
|
||
{
|
||
// this->_out->write((char *)(frame->data[1] + frame->linesize[1] * i), frame->width / 2);
|
||
this->c_write((frame->data[1] + frame->linesize[1] * i), (frame->width / 2));
|
||
}
|
||
for (int i = 0; i < frame->height / 2; i++)
|
||
{
|
||
// this->_out->write((char *)(frame->data[2] + frame->linesize[2] * i), frame->width / 2);
|
||
this->c_write((frame->data[2] + frame->linesize[2] * i), (frame->width / 2));
|
||
}
|
||
}
|
||
|
||
fprintf(stdout, "[INFO] Saving frame %3d\n", this->codec_ctx->frame_number);
|
||
av_frame_unref(this->frame);
|
||
}
|
||
return 0;
|
||
}
|
||
int vcodec::c_write(void *buf, size_t n)
|
||
{
|
||
switch (mode)
|
||
{
|
||
case FILE_READ_WRITE:
|
||
case FILE_READ_WRITE_CALL:
|
||
case IOSTREAM_READ_WRITE:
|
||
case IOSTREAM_READ_WRITE_CALL:
|
||
{
|
||
this->_out->write((char *)buf, n);
|
||
}
|
||
break;
|
||
case CUSTOM_READ_WRITE:
|
||
case CUSTOM_READ_WRITE_CALL:
|
||
{
|
||
this->custom_write(buf, n);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return 0;
|
||
}
|
||
int vcodec::c_read(void *buf, size_t n)
|
||
{
|
||
switch (mode)
|
||
{
|
||
case FILE_READ_CALL:
|
||
case FILE_READ_WRITE:
|
||
case FILE_READ_WRITE_CALL:
|
||
case IOSTREAM_READ_CALL:
|
||
case IOSTREAM_READ_WRITE:
|
||
case IOSTREAM_READ_WRITE_CALL:
|
||
{
|
||
this->_in->read((char *)buf, n);
|
||
int mk = this->_in->gcount();
|
||
return mk;
|
||
}
|
||
break;
|
||
case CUSTOM_READ_CALL:
|
||
case CUSTOM_READ_WRITE:
|
||
case CUSTOM_READ_WRITE_CALL:
|
||
{
|
||
return this->custom_read(buf, n);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
int vcodec::c_eof(void *buf, size_t n)
|
||
{
|
||
switch (mode)
|
||
{
|
||
case FILE_READ_CALL:
|
||
case FILE_READ_WRITE:
|
||
case FILE_READ_WRITE_CALL:
|
||
case IOSTREAM_READ_CALL:
|
||
case IOSTREAM_READ_WRITE:
|
||
case IOSTREAM_READ_WRITE_CALL:
|
||
{
|
||
return (int)this->_in->eof();
|
||
}
|
||
break;
|
||
case CUSTOM_READ_CALL:
|
||
case CUSTOM_READ_WRITE:
|
||
case CUSTOM_READ_WRITE_CALL:
|
||
{
|
||
return this->custom_eof(NULL, 0);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
#endif |