Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add snapshot filter mark#4571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
PioLing wants to merge5 commits intoZLMediaKit:master
base:master
Choose a base branch
Loading
fromPioLing:coding
Open

Conversation

@PioLing
Copy link
Contributor

No description provided.

Copy link

CopilotAI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Pull request overview

This PR adds watermarking functionality to video frame snapshots by integrating FFmpeg's filter graph API to overlay text (specifically "ZLMediaKit") on saved JPEG/PNG images. The implementation extends thesaveFrame function with optional parameters for custom dimensions and font paths, and introduces a fallback mechanism for system fonts across different platforms.

Key Changes

  • Adds AVFilter library integration with filter graph for text overlay on snapshot images
  • ExtendssaveFrame API with optional width, height, and font_path parameters for customizable output
  • Implements cross-platform font fallback logic (Linux, macOS, Windows)

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 9 comments.

FileDescription
src/Codec/Transcode.hAdds AVFilter includes and extends saveFrame signature with w, h, and font_path parameters
src/Codec/Transcode.cppImplements filter graph setup, drawtext filter configuration, and font path resolution for watermarking
CMakeLists.txtAdds AVFILTER library dependency detection and linking

💡Add Copilot custom instructions for smarter, more guided reviews.Learn how to get started.

* @param filename 保存文件路径
* @param fmt jpg:AV_PIX_FMT_YUVJ420P,PNG:AV_PIX_FMT_RGB24
* @param w h 图片大小,默认和输入源一致
* @param font_path

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The@param font_path documentation is incomplete. It should describe what the parameter is for (e.g., "Path to custom font file for watermark text. If not provided or invalid, falls back to system default fonts.").

Suggested change
* @paramfont_path
* @paramfont_pathPathtocustomfontfileforwatermarktext.Ifnotprovidedorinvalid,fallsbacktosystemdefaultfonts.

Copilot uses AI. Check for mistakes.
ss <<"Could not open the file" << filename;
buffersrc =avfilter_get_by_name("buffer");

if (ret =avfilter_graph_create_filter(&buffersrc_ctx, buffersrc,"in", args,NULL, _filter_graph.get()) <0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Operator precedence error: The assignmentret = avfilter_graph_create_filter(...) < 0 evaluates asret = (avfilter_graph_create_filter(...) < 0), assigning a boolean toret instead of the function's return value. This breaks error reporting withffmpeg_err(ret) on line 853. Use parentheses:if ((ret = avfilter_graph_create_filter(...)) < 0).

Copilot uses AI. Check for mistakes.
AVFilterContext *drawtext_ctx1 =nullptr;

const AVFilter *drawtext_filter =avfilter_get_by_name("drawtext");
if (ret =avfilter_graph_create_filter(&drawtext_ctx1, drawtext_filter,"drawtext", drawtext_args1,NULL, _filter_graph.get()) <0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Operator precedence error: The assignmentret = avfilter_graph_create_filter(...) < 0 evaluates asret = (avfilter_graph_create_filter(...) < 0), assigning a boolean toret instead of the function's return value. This breaks error reporting withffmpeg_err(ret) on line 868. Use parentheses:if ((ret = avfilter_graph_create_filter(...)) < 0).

Suggested change
if (ret = avfilter_graph_create_filter(&drawtext_ctx1, drawtext_filter,"drawtext", drawtext_args1,NULL, _filter_graph.get()) <0) {
if ((ret = avfilter_graph_create_filter(&drawtext_ctx1, drawtext_filter,"drawtext", drawtext_args1,NULL, _filter_graph.get())) <0) {

Copilot uses AI. Check for mistakes.
return make_tuple<bool, std::string>(false, ss.data());
}

if (ret =av_buffersrc_add_frame_flags(buffersrc_ctx, new_frame->get(),0) <0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Operator precedence error: The assignmentret = av_buffersrc_add_frame_flags(...) < 0 evaluates asret = (av_buffersrc_add_frame_flags(...) < 0), assigning a boolean toret instead of the function's return value. This breaks error reporting withffmpeg_err(ret) on line 883. Use parentheses:if ((ret = av_buffersrc_add_frame_flags(...)) < 0).

Suggested change
if (ret = av_buffersrc_add_frame_flags(buffersrc_ctx, new_frame->get(), 0) < 0) {
if ((ret = av_buffersrc_add_frame_flags(buffersrc_ctx, new_frame->get(), 0)) < 0) {

Copilot uses AI. Check for mistakes.
while (avcodec_receive_packet(jpeg_codec_ctx.get(), pkt.get()) ==0) {
fwrite(pkt.get()->data, pkt.get()->size,1, tmp_save_file_jpg.get());
buffersink =avfilter_get_by_name("buffersink");
if (ret =avfilter_graph_create_filter(&buffersink_ctx, buffersink,"out",NULL,NULL, _filter_graph.get()) <0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Operator precedence error: The assignmentret = avfilter_graph_create_filter(...) < 0 evaluates asret = (avfilter_graph_create_filter(...) < 0), assigning a boolean toret instead of the function's return value. This breaks error reporting withffmpeg_err(ret) on line 860. Use parentheses:if ((ret = avfilter_graph_create_filter(...)) < 0).

Suggested change
if (ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink,"out",NULL,NULL, _filter_graph.get()) <0) {
if ((ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink,"out",NULL,NULL, _filter_graph.get())) <0) {

Copilot uses AI. Check for mistakes.
return make_tuple<bool, std::string>(false, ss.data());
}

if (ret =avfilter_link(buffersrc_ctx,0, drawtext_ctx1,0) <0 ||avfilter_link(drawtext_ctx1,0, buffersink_ctx,0) <0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Operator precedence error and incorrect error tracking: The first assignmentret = avfilter_link(...) < 0 evaluates asret = (avfilter_link(...) < 0), assigning a boolean. Additionally, if the secondavfilter_link fails,ret won't contain its error code. Split into separate conditions or use:if ((ret = avfilter_link(buffersrc_ctx, 0, drawtext_ctx1, 0)) < 0 || (ret = avfilter_link(drawtext_ctx1, 0, buffersink_ctx, 0)) < 0).

Suggested change
if (ret = avfilter_link(buffersrc_ctx,0, drawtext_ctx1,0) <0 || avfilter_link(drawtext_ctx1,0, buffersink_ctx,0) <0) {
if ((ret = avfilter_link(buffersrc_ctx,0, drawtext_ctx1,0)) <0 ||(ret =avfilter_link(drawtext_ctx1,0, buffersink_ctx,0)) <0) {

Copilot uses AI. Check for mistakes.
return make_tuple<bool, std::string>(false, ss.data());
}

if (ret =avfilter_graph_config(_filter_graph.get(),NULL) <0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Operator precedence error: The assignmentret = avfilter_graph_config(...) < 0 evaluates asret = (avfilter_graph_config(...) < 0), assigning a boolean toret instead of the function's return value. This breaks error reporting withffmpeg_err(ret) on line 878. Use parentheses:if ((ret = avfilter_graph_config(...)) < 0).

Suggested change
if (ret = avfilter_graph_config(_filter_graph.get(),NULL) <0) {
if ((ret = avfilter_graph_config(_filter_graph.get(),NULL)) <0) {

Copilot uses AI. Check for mistakes.
}

if (ret =av_buffersrc_add_frame_flags(buffersrc_ctx, new_frame->get(),0) <0) {
ss <<"av_buffersink_get_frame failed:" << ret <<"" <<ffmpeg_err(ret);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Incorrect error message: The error says "av_buffersink_get_frame failed" but the actual function being called isav_buffersrc_add_frame_flags. The message should be "av_buffersrc_add_frame_flags failed".

Suggested change
ss <<"av_buffersink_get_frame failed:" << ret <<"" << ffmpeg_err(ret);
ss <<"av_buffersrc_add_frame_flags failed:" << ret <<"" << ffmpeg_err(ret);

Copilot uses AI. Check for mistakes.
Comment on lines +887 to +892
while (av_buffersink_get_frame(buffersink_ctx, new_frame->get()) >=0) {
if (avcodec_send_frame(jpeg_codec_ctx.get(), new_frame->get()) ==0) {
while (avcodec_receive_packet(jpeg_codec_ctx.get(), pkt.get()) ==0) {
fwrite(pkt.get()->data, pkt.get()->size,1, tmp_save_file_jpg.get());
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Potential frame data corruption:new_frame is passed toav_buffersrc_add_frame_flags on line 882, then immediately reused on line 887 withav_buffersink_get_frame to retrieve the filtered frame. This overwrites the frame data. The filtered frame should be retrieved into a separate frame object to avoid data corruption.

Suggested change
while (av_buffersink_get_frame(buffersink_ctx, new_frame->get()) >= 0) {
if (avcodec_send_frame(jpeg_codec_ctx.get(), new_frame->get()) == 0) {
while (avcodec_receive_packet(jpeg_codec_ctx.get(), pkt.get()) ==0) {
fwrite(pkt.get()->data, pkt.get()->size, 1, tmp_save_file_jpg.get());
}
}
auto filtered_frame = std::make_shared<FFmpegFrame>();
while (av_buffersink_get_frame(buffersink_ctx, filtered_frame->get()) >= 0) {
if (avcodec_send_frame(jpeg_codec_ctx.get(), filtered_frame->get()) == 0) {
while (avcodec_receive_packet(jpeg_codec_ctx.get(), pkt.get()) ==0) {
fwrite(pkt.get()->data, pkt.get()->size, 1, tmp_save_file_jpg.get());
}
}
filtered_frame->unref();

Copilot uses AI. Check for mistakes.
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

Copilot code reviewCopilotCopilot left review comments

At least 1 approving review is required to merge this pull request.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

@PioLing

[8]ページ先頭

©2009-2025 Movatter.jp