ZLMediaKit/src/Codec/Transcode.h
mtdxc 73d348ea96
Some checks failed
Android / build (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Linux / build (push) Has been cancelled
macOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
修复test_player没声音和windows控制台日志不输出bug (#4484)
2025-09-30 11:05:01 +08:00

181 lines
4.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_TRANSCODE_H
#define ZLMEDIAKIT_TRANSCODE_H
#if defined(ENABLE_FFMPEG)
#include "Util/TimeTicker.h"
#include "Common/MediaSink.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "libswscale/swscale.h"
#include "libavutil/avutil.h"
#include "libavutil/pixdesc.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/imgutils.h"
#include "libavutil/frame.h"
#ifdef __cplusplus
}
#endif
#define FF_CODEC_VER_7_1 AV_VERSION_INT(61, 0, 0)
namespace mediakit {
class FFmpegFrame {
public:
using Ptr = std::shared_ptr<FFmpegFrame>;
FFmpegFrame(std::shared_ptr<AVFrame> frame = nullptr);
~FFmpegFrame();
AVFrame *get() const;
void fillPicture(AVPixelFormat target_format, int target_width, int target_height);
int getChannels() const;
private:
char *_data = nullptr;
std::shared_ptr<AVFrame> _frame;
};
class FFmpegSwr {
public:
using Ptr = std::shared_ptr<FFmpegSwr>;
# if LIBAVCODEC_VERSION_INT >= FF_CODEC_VER_7_1
FFmpegSwr(AVSampleFormat output, AVChannelLayout *ch_layout, int samplerate);
#else
FFmpegSwr(AVSampleFormat output, int channel, int channel_layout, int samplerate);
#endif
~FFmpegSwr();
FFmpegFrame::Ptr inputFrame(const FFmpegFrame::Ptr &frame);
private:
# if LIBAVCODEC_VERSION_INT >= FF_CODEC_VER_7_1
AVChannelLayout _target_ch_layout;
#else
int _target_channels;
int _target_channel_layout;
#endif
int _target_samplerate;
AVSampleFormat _target_format;
SwrContext *_ctx = nullptr;
toolkit::ResourcePool<FFmpegFrame> _swr_frame_pool;
};
class TaskManager {
public:
virtual ~TaskManager();
void setMaxTaskSize(size_t size);
void stopThread(bool drop_task);
protected:
void startThread(const std::string &name);
bool addEncodeTask(std::function<void()> task);
bool addDecodeTask(bool key_frame, std::function<void()> task);
bool isEnabled() const;
private:
void onThreadRun(const std::string &name);
private:
class ThreadExitException : public std::runtime_error {
public:
ThreadExitException() : std::runtime_error("exit") {}
};
private:
bool _decode_drop_start = false;
bool _exit = false;
size_t _max_task = 30;
std::mutex _task_mtx;
toolkit::semaphore _sem;
toolkit::List<std::function<void()> > _task;
std::shared_ptr<std::thread> _thread;
};
class FFmpegDecoder : public TaskManager {
public:
using Ptr = std::shared_ptr<FFmpegDecoder>;
using onDec = std::function<void(const FFmpegFrame::Ptr &)>;
FFmpegDecoder(const Track::Ptr &track, int thread_num = 2, const std::vector<std::string> &codec_name = {});
~FFmpegDecoder() override;
bool inputFrame(const Frame::Ptr &frame, bool live, bool async, bool enable_merge = true);
void setOnDecode(onDec cb);
void flush();
const AVCodecContext *getContext() const;
private:
void onDecode(const FFmpegFrame::Ptr &frame);
bool inputFrame_l(const Frame::Ptr &frame, bool live, bool enable_merge);
bool decodeFrame(const char *data, size_t size, uint64_t dts, uint64_t pts, bool live, bool key_frame);
private:
// default merge frame
bool _do_merger = true;
toolkit::Ticker _ticker;
onDec _cb;
std::shared_ptr<AVCodecContext> _context;
FrameMerger _merger{FrameMerger::h264_prefix};
toolkit::ResourcePool<FFmpegFrame> _frame_pool;
};
class FFmpegSws {
public:
using Ptr = std::shared_ptr<FFmpegSws>;
FFmpegSws(AVPixelFormat output, int width, int height);
~FFmpegSws();
FFmpegFrame::Ptr inputFrame(const FFmpegFrame::Ptr &frame);
int inputFrame(const FFmpegFrame::Ptr &frame, uint8_t *data);
private:
FFmpegFrame::Ptr inputFrame(const FFmpegFrame::Ptr &frame, int &ret, uint8_t *data);
private:
int _target_width = 0;
int _target_height = 0;
int _src_width = 0;
int _src_height = 0;
SwsContext *_ctx = nullptr;
AVPixelFormat _src_format = AV_PIX_FMT_NONE;
AVPixelFormat _target_format = AV_PIX_FMT_NONE;
toolkit::ResourcePool<FFmpegFrame> _sws_frame_pool;
};
class FFmpegUtils {
public:
/**
* 保持图片为jpeg或png
* @param frame 解码后的帧
* @param filename 保存文件路径
* @param fmt jpg:AV_PIX_FMT_YUVJ420PPNG:AV_PIX_FMT_RGB24
* @return
*/
static std::tuple<bool, std::string> saveFrame(const FFmpegFrame::Ptr &frame, const char *filename, AVPixelFormat fmt = AV_PIX_FMT_YUVJ420P);
};
}//namespace mediakit
#endif// ENABLE_FFMPEG
#endif //ZLMEDIAKIT_TRANSCODE_H