https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff
#ifndef __CSWR_H__
#define __CSWR_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <libswresample/swresample.h>
#ifdef __cplusplus
}
#endif
#include <string>
#include <mutex>
class CSwr
{
public:
~CSwr();
// 状态
enum STATUS { STOP, LOCKED };
// 设置源参数
bool set_src_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err);
// 设置目标参数
bool set_dst_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err);
// 锁定设置
bool lock_opt(std::string& err);
// 解除锁定
bool unlock_opt(std::string& err);
// 转换
int convert(uint8_t** out, int out_count, const uint8_t** in, int in_count, std::string& err);
private:
STATUS status_ = STOP;
std::recursive_mutex mutex_;
SwrContext* swrctx_ = nullptr;
AVSampleFormat src_sam_fmt_ = AV_SAMPLE_FMT_NONE;
AVSampleFormat dst_sam_fmt_ = AV_SAMPLE_FMT_NONE;
int64_t src_layout_ = AV_CH_LAYOUT_MONO;
int64_t dst_layout_ = AV_CH_LAYOUT_MONO;
int src_rate_ = 0;
int dst_rate_ = 0;
};
#endif//__CSWR_H__
#include "common.h"
#include "CSwr.h"
CSwr::~CSwr()
{
std::string err;
unlock_opt(err);
}
bool CSwr::set_src_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err)
{
LOCK();
CHECKSTOP(err);
src_layout_ = layout;
src_rate_ = rate;
src_sam_fmt_ = fmt;
return true;
}
bool CSwr::set_dst_opt(int64_t layout, int rate, enum AVSampleFormat fmt, std::string& err)
{
LOCK();
CHECKSTOP(err);
dst_layout_ = layout;
dst_rate_ = rate;
dst_sam_fmt_ = fmt;
return true;
}
bool CSwr::lock_opt(std::string& err)
{
LOCK();
CHECKSTOP(err);
swrctx_ = swr_alloc_set_opts(swrctx_, dst_layout_, dst_sam_fmt_, dst_rate_, src_layout_, src_sam_fmt_, src_rate_, 0, nullptr);
if (swrctx_ == nullptr)
{
err = "swr_alloc_set_opts(swrctx_, dst_layout_, dst_sam_fmt_, dst_rate_, src_layout_, src_sam_fmt_, src_rate_, 0, nullptr) return nullptr.";
return false;
}
int ret = swr_init(swrctx_);
CHECKFFRET(ret);
status_ = LOCKED;
return true;
}
bool CSwr::unlock_opt(std::string& err)
{
LOCK();
swr_free(&swrctx_);
status_ = STOP;
src_sam_fmt_ = AV_SAMPLE_FMT_NONE;
dst_sam_fmt_ = AV_SAMPLE_FMT_NONE;
src_layout_ = AV_CH_LAYOUT_MONO;
dst_layout_ = AV_CH_LAYOUT_MONO;
src_rate_ = 0;
dst_rate_ = 0;
return true;
}
int CSwr::convert(uint8_t** out, int out_count, const uint8_t** in, int in_count, std::string& err)
{
LOCK();
CHECKNOTSTOP(err);
int ret = swr_convert(swrctx_, out, out_count, in, in_count);
CHECKFFRET(ret);
return ret;
}
#include "CDecode.h"
#include "CSws.h"
#include "CSwr.h"
#include <iostream>
#include <fstream>
CSws g_sws;
uint8_t* g_pointers[4] = { 0 };
int g_linesizes[4] = { 0 };
CSwr g_swr;
uint8_t** g_data = nullptr;
int g_linesize = 0;
int64_t g_layout = AV_CH_LAYOUT_STEREO;
int g_rate = 44100;
enum AVSampleFormat g_fmt = AV_SAMPLE_FMT_DBLP;
void DecStatusCB(CDecode::STATUS status, std::string err, void* param)
{
std::cout << std::this_thread::get_id() << " got a status " << status << std::endl;
}
void DecFrameCB(const AVFrame* frame, CDecode::FRAMETYPE frametype, void* param)
{
//std::cout << std::this_thread::get_id() << " got a frame." << frametype << std::endl;
if (frametype == CDecode::FRAMETYPE::VIDEO)
{
if (frame->format == AV_PIX_FMT_YUV420P)
{
static std::ofstream video("out.rgb", std::ios::binary | std::ios::trunc);
static int i = 0;
if (++i > 9)
return;
/*
video.write(reinterpret_cast<const char*>(frame->data[0]), frame->linesize[0] * frame->height);
video.write(reinterpret_cast<const char*>(frame->data[1]), frame->linesize[1] * frame->height / 2);
video.write(reinterpret_cast<const char*>(frame->data[2]), frame->linesize[2] * frame->height / 2);
*/
std::string err;
// 将输出翻转
g_pointers[0] += g_linesizes[0] * (240 - 1);
g_linesizes[0] *= -1;
// 转换
g_sws.scale(frame->data, frame->linesize, 0, frame->height, g_pointers, g_linesizes, err);
// 还原指针,以便拷贝数据
g_linesizes[0] *= -1;
g_pointers[0] -= g_linesizes[0] * (240 - 1);
video.write(reinterpret_cast<const char*>(g_pointers[0]), g_linesizes[0] * 240);
}
}
else if (frametype == CDecode::FRAMETYPE::AUDIO)
{
if (frame->format == AV_SAMPLE_FMT_FLTP)
{
static std::ofstream audio("out.pcm", std::ios::binary | std::ios::trunc);
std::string err;
int ret = g_swr.convert(g_data, g_linesize, (const uint8_t * *)frame->data, frame->nb_samples, err);
auto size = av_get_bytes_per_sample(g_fmt);
for (int i = 0; i < ret; ++i)
{
for (int j = 0; j < av_get_channel_layout_nb_channels(g_layout); ++j)
{
audio.write(reinterpret_cast<const char*>(g_data[j] + size * i), size);
}
}
}
}
}
int main(int argc, char* argv[])
{
std::string err;
bool ret = false;
ret = g_sws.set_src_opt(AV_PIX_FMT_YUV420P, 576, 432, err);
ret = g_sws.set_dst_opt(AV_PIX_FMT_RGB24, 320, 240, err);
ret = g_sws.lock_opt(err);
int size = av_image_alloc(g_pointers, g_linesizes, 320, 240, AV_PIX_FMT_RGB24, 1);
ret = g_swr.set_src_opt(AV_CH_LAYOUT_STEREO, 48000, AV_SAMPLE_FMT_FLTP, err);
ret = g_swr.set_dst_opt(g_layout, g_rate, g_fmt, err);
ret = g_swr.lock_opt(err);
size = av_samples_alloc_array_and_samples(&g_data, &g_linesize, av_get_channel_layout_nb_channels(g_layout), g_rate, g_fmt, 0);
CDecode decode;
ret = decode.set_input("in.flv", err);
ret = decode.set_dec_callback(DecFrameCB, nullptr, err);
ret = decode.set_dec_status_callback(DecStatusCB, nullptr, err);
int i = 0;
while (i++ < 1)
{
ret = decode.begindecode(err);
std::cout << "input to stop decoding." << std::endl;
getchar();
ret = decode.stopdecode(err);
}
ret = g_sws.unlock_opt(err);
av_freep(&g_pointers[0]);
ret = g_swr.unlock_opt(err);
if (g_data)
av_freep(&g_data[0]);
av_freep(&g_data);
return 0;
}