https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cffios
#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; }