mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-07-04 09:47:33 +08:00
Optimize the code related to decoding and screenshot (#4106)
Co-authored-by: xia-chu <771730766@qq.com>
This commit is contained in:
@@ -349,7 +349,57 @@ void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) {
|
||||
}
|
||||
}
|
||||
|
||||
void FFmpegSnap::makeSnap(const string &play_url, const string &save_path, float timeout_sec, const onSnap &cb) {
|
||||
#if defined(ENABLE_FFMPEG)
|
||||
#include "Player/MediaPlayer.h"
|
||||
#include "Codec/Transcode.h"
|
||||
|
||||
static void makeSnapAsync(const string &play_url, const string &save_path, float timeout_sec, const FFmpegSnap::onSnap &cb) {
|
||||
struct Holder {
|
||||
MediaPlayer::Ptr player;
|
||||
};
|
||||
auto holder = std::make_shared<Holder>();
|
||||
holder->player = std::make_shared<MediaPlayer>();
|
||||
(*holder->player)[mediakit::Client::kTimeoutMS] = timeout_sec * 1000;
|
||||
|
||||
holder->player->setOnPlayResult([holder, save_path, cb, timeout_sec](const SockException &ex) mutable {
|
||||
onceToken token(nullptr, [&]() { holder->player = nullptr; });
|
||||
auto video = ex ? nullptr : dynamic_pointer_cast<VideoTrack>(holder->player->getTrack(TrackVideo, false));
|
||||
if (!video) {
|
||||
cb(false, ex ? ex.what() : "none video track");
|
||||
return;
|
||||
}
|
||||
auto decoder = std::make_shared<FFmpegDecoder>(video);
|
||||
auto new_holder = std::make_shared<Holder>(*holder);
|
||||
auto timer = EventPollerPool::Instance().getPoller()->doDelayTask(1000 * timeout_sec, [new_holder]() {
|
||||
// 防止解码失败导致播放器无法释放
|
||||
new_holder->player = nullptr;
|
||||
return 0;
|
||||
});
|
||||
auto success = false;
|
||||
decoder->setOnDecode([save_path, new_holder, cb, success, timer](const FFmpegFrame::Ptr &frame) mutable {
|
||||
if (success) {
|
||||
return;
|
||||
}
|
||||
onceToken token(nullptr, [&]() { new_holder->player = nullptr; timer->cancel(); });
|
||||
auto ret = FFmpegUtils::saveFrame(frame, save_path.data());
|
||||
success = std::get<0>(ret);
|
||||
cb(success, std::get<1>(ret));
|
||||
});
|
||||
video->addDelegate([decoder](const Frame::Ptr &frame) { return decoder->inputFrame(frame, false, true); });
|
||||
});
|
||||
holder->player->play(play_url);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void FFmpegSnap::makeSnap(bool async, const string &play_url, const string &save_path, float timeout_sec, const onSnap &cb) {
|
||||
#if defined(ENABLE_FFMPEG)
|
||||
if (async) {
|
||||
makeSnapAsync(play_url, save_path, timeout_sec, cb);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GET_CONFIG(string, ffmpeg_bin, FFmpeg::kBin);
|
||||
GET_CONFIG(string, ffmpeg_snap, FFmpeg::kSnap);
|
||||
GET_CONFIG(string, ffmpeg_log, FFmpeg::kLog);
|
||||
|
||||
@@ -26,17 +26,20 @@ namespace FFmpeg {
|
||||
class FFmpegSnap {
|
||||
public:
|
||||
using onSnap = std::function<void(bool success, const std::string &err_msg)>;
|
||||
// / 创建截图 [AUTO-TRANSLATED:6d334c49]
|
||||
// / Create a screenshot
|
||||
// / \param play_url 播放url地址,只要FFmpeg支持即可 [AUTO-TRANSLATED:609d4de4]
|
||||
// / \param play_url The playback URL address, as long as FFmpeg supports it
|
||||
// / \param save_path 截图jpeg文件保存路径 [AUTO-TRANSLATED:0fc0ac0d]
|
||||
// / \param save_path The path to save the screenshot JPEG file
|
||||
// / \param timeout_sec 生成截图超时时间(防止阻塞太久) [AUTO-TRANSLATED:0dcc0095]
|
||||
// / \param timeout_sec Timeout for generating the screenshot (to prevent blocking for too long)
|
||||
// / \param cb 生成截图成功与否回调 [AUTO-TRANSLATED:5b4b93c9]
|
||||
// / \param cb Callback for whether the screenshot was generated successfully
|
||||
static void makeSnap(const std::string &play_url, const std::string &save_path, float timeout_sec, const onSnap &cb);
|
||||
/**
|
||||
* 创建截图 [AUTO-TRANSLATED:6d334c49]
|
||||
* Create a screenshot
|
||||
* @param async 是否使用异步截图方式(非ffmpeg命令行,而是使用zlm api,但是仅限于zlm播放器支持的拉流协议)
|
||||
* @param play_url 播放url地址,只要FFmpeg支持即可 [AUTO-TRANSLATED:609d4de4]
|
||||
* @param play_url The playback URL address, as long as FFmpeg supports it
|
||||
* @param save_path 截图jpeg文件保存路径 [AUTO-TRANSLATED:0fc0ac0d]
|
||||
* @param save_path The path to save the screenshot JPEG file
|
||||
* @param timeout_sec 生成截图超时时间(防止阻塞太久) [AUTO-TRANSLATED:0dcc0095]
|
||||
* @param timeout_sec Timeout for generating the screenshot (to prevent blocking for too long)
|
||||
* @param cb 生成截图成功与否回调 [AUTO-TRANSLATED:5b4b93c9]
|
||||
* @param cb Callback for whether the screenshot was generated successfully
|
||||
*/
|
||||
static void makeSnap(bool async, const std::string &play_url, const std::string &save_path, float timeout_sec, const onSnap &cb);
|
||||
|
||||
private:
|
||||
FFmpegSnap() = delete;
|
||||
|
||||
@@ -151,10 +151,10 @@ void StackPlayer::play() {
|
||||
// auto audioTrack = std::dynamic_pointer_cast<mediakit::AudioTrack>(strongPlayer->getTrack(mediakit::TrackAudio, false));
|
||||
|
||||
if (videoTrack) {
|
||||
// 如果每次不同 可以加个时间戳 time(NULL);
|
||||
// TODO:添加使用显卡还是cpu解码的判断逻辑 [AUTO-TRANSLATED:44bef37a]
|
||||
// TODO: Add logic to determine whether to use GPU or CPU decoding
|
||||
auto decoder = std::make_shared<mediakit::FFmpegDecoder>(
|
||||
videoTrack, 0, std::vector<std::string>{"h264", "hevc"});
|
||||
auto decoder = std::make_shared<mediakit::FFmpegDecoder>(videoTrack, 0, std::vector<std::string> { "h264", "hevc" });
|
||||
|
||||
decoder->setOnDecode([weakSelf](const mediakit::FFmpegFrame::Ptr& frame) mutable {
|
||||
auto self = weakSelf.lock();
|
||||
|
||||
@@ -2047,7 +2047,7 @@ void installWebApi() {
|
||||
// 启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件 [AUTO-TRANSLATED:7d589e3f]
|
||||
// Start the FFmpeg process, start taking screenshots, generate temporary files, replace them with formal files after successful screenshots
|
||||
auto new_snap_tmp = new_snap + ".tmp";
|
||||
FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success, const string &err_msg) {
|
||||
FFmpegSnap::makeSnap(allArgs["async"], allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success, const string &err_msg) {
|
||||
if (!success) {
|
||||
// 生成截图失败,可能残留空文件 [AUTO-TRANSLATED:c96a4468]
|
||||
// Screenshot generation failed, there may be residual empty files
|
||||
|
||||
Reference in New Issue
Block a user