用ffmpeg给视频添加水印的命令为:

    1. ffmpeg -i in.mp4 -i xxx.png -filter_complex "overlay=5:5" out.mp4

    代码实现如下, 主要是用了参考了ffmpeg.c里面的filter_complex的代码:

    1. #include <unistd.h>
    2. #include <stdio.h>
    3. #include <assert.h>
    4. #include <libavcodec/avcodec.h>
    5. #include <libavformat/avformat.h>
    6. #include <libavfilter/avfiltergraph.h>
    7. #include <libavfilter/avcodec.h>
    8. #include <libavfilter/buffersink.h>
    9. #include <libavfilter/buffersrc.h>
    10. #include <libswscale/swscale.h>
    11. const char *filter_descr = "overlay=5:5";
    12. #define ENABLE_YUV_FILE 1
    13. AVFormatContext *input_fmt_ctx;
    14. AVCodecContext *input_dec_ctx;
    15. AVFormatContext *overlay_fmt_ctx;
    16. AVCodecContext *overlay_dec_ctx;
    17. int input_video_stream_idx, overlay_video_stream_idx;
    18. AVFilterGraph *filter_graph;
    19. AVFilterInOut *inputs;
    20. AVFilterInOut *outputs;
    21. AVFilterContext *buffersrc_ctx;
    22. AVFilterContext *bufferoverlay_ctx;
    23. AVFilterContext *buffersink_ctx;
    24. int ret;
    25. int got_frame;
    26. int video_eof_reached = 0;
    27. int overlay_eof_reached = 0;
    28. int active_stream_index = -1;
    29. FILE* fp_yuv;
    30. void yuv420p_save(AVFrame *pFrame);
    31. int video_transcode_step(AVFrame* mVideoFrame);
    32. int overlay_transcode_step(AVFrame* mOverlayFrame);
    33. int video_output_eof_packet(const char* tag,
    34. AVStream* ist, AVFilterContext* ifilter);
    35. static int open_input_file(const char *filename)
    36. {
    37. int ret;
    38. AVCodec *dec;
    39. if ((ret = avformat_open_input(&input_fmt_ctx, filename, NULL, NULL)) < 0) {
    40. av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
    41. return ret;
    42. }
    43. if ((ret = avformat_find_stream_info(input_fmt_ctx, NULL)) < 0) {
    44. av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
    45. return ret;
    46. }
    47. /* select the video stream */
    48. ret = av_find_best_stream(input_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    49. if (ret < 0) {
    50. av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
    51. return ret;
    52. }
    53. input_video_stream_idx = ret;
    54. input_dec_ctx = input_fmt_ctx->streams[input_video_stream_idx]->codec;
    55. /* init the video decoder */
    56. if ((ret = avcodec_open2(input_dec_ctx, dec, NULL)) < 0) {
    57. av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
    58. return ret;
    59. }
    60. return 0;
    61. }
    62. static int open_overlay_file(const char *filename)
    63. {
    64. int ret;
    65. AVCodec *dec;
    66. if ((ret = avformat_open_input(&overlay_fmt_ctx, filename, NULL, NULL)) < 0) {
    67. av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
    68. return ret;
    69. }
    70. if ((ret = avformat_find_stream_info(overlay_fmt_ctx, NULL)) < 0) {
    71. av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
    72. return ret;
    73. }
    74. /* select the video stream */
    75. ret = av_find_best_stream(overlay_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    76. if (ret < 0) {
    77. av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
    78. return ret;
    79. }
    80. overlay_video_stream_idx = ret;
    81. overlay_dec_ctx = overlay_fmt_ctx->streams[overlay_video_stream_idx]->codec;
    82. /* init the video decoder */
    83. if ((ret = avcodec_open2(overlay_dec_ctx, dec, NULL)) < 0) {
    84. av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
    85. return ret;
    86. }
    87. printf("overlay format = %s\n", overlay_fmt_ctx->iformat->name);
    88. return 0;
    89. }
    90. static int video_config_input_filter(AVFilterInOut* inputs, AVFilterContext** input_filter_ctx)
    91. {
    92. char args[512];
    93. memset(args, 0, sizeof(args));
    94. AVFilterContext *first_filter = inputs->filter_ctx;
    95. int pad_idx = inputs->pad_idx;
    96. AVFilter *filter = avfilter_get_by_name("buffer");
    97. // AVRational time_base = input_dec_ctx->time_base;
    98. AVStream* video_st = input_fmt_ctx->streams[input_video_stream_idx];
    99. AVRational time_base = video_st->time_base;
    100. snprintf(args, sizeof(args),
    101. "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d:sws_param=flags=%d:frame_rate=%d/%d",
    102. input_dec_ctx->width, input_dec_ctx->height, input_dec_ctx->pix_fmt,
    103. input_dec_ctx->time_base.num, input_dec_ctx->time_base.den,
    104. input_dec_ctx->sample_aspect_ratio.num, input_dec_ctx->sample_aspect_ratio.den,
    105. SWS_BILINEAR + ((video_st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0),
    106. video_st->r_frame_rate.num, video_st->r_frame_rate.den);
    107. printf("input args = %s\n", args);
    108. ret = avfilter_graph_create_filter(input_filter_ctx, filter, "src_in", args, NULL, filter_graph);
    109. if (ret < 0 ) {
    110. printf("video config input filter fail.\n");
    111. return -1;
    112. }
    113. ret = avfilter_link(*input_filter_ctx, 0, first_filter, pad_idx);
    114. assert(ret >= 0);
    115. printf("video_config_input_filter avfilter_link ret = %d\n", ret);
    116. return ret;
    117. }
    118. static int video_config_overlay_filter(AVFilterInOut* inputs, AVFilterContext** overlay_filter_ctx )
    119. {
    120. char args[512];
    121. memset(args, 0, sizeof(args));
    122. AVFilterContext *first_filter = inputs->filter_ctx;
    123. int pad_idx = inputs->pad_idx;
    124. AVFilter *filter = avfilter_get_by_name("buffer");
    125. //AVRational time_base = overlay_dec_ctx->time_base;
    126. AVStream* overlay_st = overlay_fmt_ctx->streams[overlay_video_stream_idx];
    127. AVRational time_base = overlay_st->time_base;
    128. snprintf(args, sizeof(args),
    129. "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d:sws_param=flags=%d:frame_rate=%d/%d",
    130. overlay_dec_ctx->width, overlay_dec_ctx->height, overlay_dec_ctx->pix_fmt,
    131. time_base.num, time_base.den,
    132. overlay_dec_ctx->sample_aspect_ratio.num, overlay_dec_ctx->sample_aspect_ratio.den,
    133. SWS_BILINEAR + ((overlay_st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0),
    134. overlay_st->r_frame_rate.num, overlay_st->r_frame_rate.den);
    135. printf("overlay args = %s\n", args);
    136. ret = avfilter_graph_create_filter(overlay_filter_ctx, filter, "overlay_in", args, NULL, filter_graph);
    137. if (ret < 0 ) {
    138. printf("video config overlay filter fail.\n");
    139. return -1;
    140. }
    141. ret = avfilter_link(*overlay_filter_ctx, 0, first_filter, pad_idx);
    142. assert(ret >= 0);
    143. printf("video_config_overlay_filter ret = %d\n", ret);
    144. avfilter_inout_free(&inputs);
    145. return ret;
    146. }
    147. static int video_config_output_filter(AVFilterInOut* outputs, AVFilterContext** out_filter_ctx)
    148. {
    149. char args[512];
    150. AVFilterContext *last_filter = outputs->filter_ctx;
    151. int pad_idx = outputs->pad_idx;
    152. AVFilter *buffersink = avfilter_get_by_name("ffbuffersink");
    153. int ret = avfilter_graph_create_filter(out_filter_ctx, buffersink, "video_out", NULL, NULL, filter_graph);
    154. assert(ret >= 0);
    155. if (ret < 0)
    156. return ret;
    157. ret = avfilter_link(last_filter, pad_idx, *out_filter_ctx, 0);
    158. assert(ret >= 0);
    159. if (ret < 0)
    160. return ret;
    161. avfilter_inout_free(&outputs);
    162. return 0;
    163. }
    164. static int init_input_filters()
    165. {
    166. filter_graph->scale_sws_opts = av_strdup("flags=0x4");
    167. av_opt_set(filter_graph, "aresample_swr_opts", "", 0);
    168. ret = avfilter_graph_parse2(filter_graph, filter_descr, &inputs, &outputs);
    169. assert(inputs && inputs->next && !inputs->next->next);
    170. ret = video_config_input_filter(inputs, &buffersrc_ctx);
    171. ret = video_config_overlay_filter(inputs->next, &bufferoverlay_ctx);
    172. return ret;
    173. }
    174. static int init_output_filters()
    175. {
    176. return video_config_output_filter(outputs, &buffersink_ctx);
    177. }
    178. int reap_filters() {
    179. AVFilterBufferRef *picref;
    180. while (1) {
    181. ret = av_buffersink_get_buffer_ref(buffersink_ctx, &picref, AV_BUFFERSINK_FLAG_NO_REQUEST);
    182. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
    183. //printf("reap_filters fail ret = %d\n", ret);
    184. return 0; // no frame filtered.
    185. }
    186. printf("samplesref -------------------\n");
    187. AVFrame* filtered_frame = avcodec_alloc_frame();
    188. avcodec_get_frame_defaults(filtered_frame);
    189. avfilter_copy_buf_props(filtered_frame, picref);
    190. yuv420p_save(filtered_frame);
    191. avfilter_unref_bufferp(&picref);
    192. }
    193. }
    194. int transcode_from_filter(AVFilterContext** ifilters, int* eof_reached_arr, int* active_stream_indext) {
    195. int ret = 0;
    196. ret = avfilter_graph_request_oldest(filter_graph);
    197. if (ret >= 0) {
    198. return ret;
    199. }
    200. if (ret == AVERROR_EOF) {
    201. return ret;
    202. }
    203. if (ret != AVERROR(EAGAIN)) {
    204. return ret;
    205. }
    206. int nb_requests_max = 0;
    207. int i;
    208. for (i = 0; i < 2; i++) {
    209. int eof_reached = eof_reached_arr[i];
    210. if (eof_reached) {
    211. continue;
    212. }
    213. AVFilterContext* ifilter = ifilters[i];
    214. int nb_requests = av_buffersrc_get_nb_failed_requests(ifilter);
    215. if (nb_requests > nb_requests_max) {
    216. nb_requests_max = nb_requests;
    217. *active_stream_indext = i;
    218. }
    219. }
    220. return ret;
    221. }
    222. int main()
    223. {
    224. avcodec_register_all();
    225. av_register_all();
    226. avfilter_register_all();
    227. avformat_network_init();
    228. char* video_file = "outFileSrc.mp4";
    229. char* overlay_video_file = "my_logo.png"; // light1.mp4
    230. #if ENABLE_YUV_FILE
    231. const char* yuvFile = "outWater.yuv";
    232. fp_yuv = fopen(yuvFile, "wb");
    233. #endif
    234. open_input_file(video_file);
    235. open_overlay_file(overlay_video_file);
    236. filter_graph = avfilter_graph_alloc();
    237. if (!filter_graph) {
    238. printf("filter graph alloc fail.\n");
    239. return -1;
    240. }
    241. init_input_filters();
    242. init_output_filters();
    243. if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
    244. return ret;
    245. AVFrame* mVideoFrame = avcodec_alloc_frame();
    246. AVFrame* mOverlayFrame = avcodec_alloc_frame();
    247. while(1) {
    248. if (video_eof_reached && overlay_eof_reached) {
    249. printf("stream EOF.\n");
    250. break;
    251. }
    252. AVFilterContext* ifilters[] = {buffersrc_ctx, bufferoverlay_ctx};
    253. int eof_reacheds[] = {video_eof_reached, overlay_eof_reached};
    254. ret = transcode_from_filter(ifilters, eof_reacheds, &active_stream_index);
    255. if (ret >= 0) {
    256. ret = reap_filters();
    257. assert(ret >= 0);
    258. continue;
    259. }
    260. if (ret == AVERROR_EOF) {
    261. ret = reap_filters();
    262. assert(ret >= 0);
    263. continue;
    264. }
    265. if (ret == AVERROR(EAGAIN) && active_stream_index < 0) {
    266. continue;
    267. }
    268. assert(active_stream_index >= 0);
    269. printf("active_stream_index = %d\n", active_stream_index);
    270. if (active_stream_index == 0) {
    271. video_transcode_step(mVideoFrame);
    272. continue;
    273. }
    274. overlay_transcode_step(mOverlayFrame);
    275. }
    276. if (input_dec_ctx)
    277. avcodec_close(input_dec_ctx);
    278. avformat_close_input(&input_fmt_ctx);
    279. if (overlay_dec_ctx)
    280. avcodec_close(overlay_dec_ctx);
    281. avformat_close_input(&overlay_fmt_ctx);
    282. printf("my_filtering_video3 end -------\n");
    283. return 0;
    284. }
    285. int video_transcode_step(AVFrame* mVideoFrame) {
    286. int ret = 0;
    287. AVPacket pkt;
    288. ret = av_read_frame(input_fmt_ctx, &pkt);
    289. if (ret == AVERROR(EAGAIN)) {
    290. return 0;
    291. }
    292. if (ret < 0) {
    293. video_eof_reached = 1;
    294. assert(ret == AVERROR_EOF);
    295. ret = video_output_eof_packet("video_eof", input_fmt_ctx->streams[input_video_stream_idx], buffersrc_ctx);
    296. assert (ret >= 0);
    297. return ret;
    298. }
    299. if (pkt.stream_index != input_video_stream_idx) {
    300. // av_free(&pkt);
    301. return ret;
    302. }
    303. ret = avcodec_decode_video2(input_dec_ctx, mVideoFrame, &got_frame, &pkt);
    304. if (ret < 0) {
    305. printf("Error decoding input video\n");
    306. }
    307. if (got_frame) {
    308. int64_t best_effort_timestamp = av_frame_get_best_effort_timestamp(mVideoFrame);
    309. mVideoFrame->pts = best_effort_timestamp;
    310. if (av_buffersrc_add_frame(buffersrc_ctx, mVideoFrame, AV_BUFFERSRC_FLAG_PUSH) < 0) {
    311. av_log(NULL, AV_LOG_ERROR, "Error while feeding the video filtergraph\n");
    312. return -1;
    313. }
    314. reap_filters();
    315. }
    316. return 0;
    317. }
    318. int overlay_transcode_step(AVFrame* mOverlayFrame) {
    319. int ret = 0;
    320. AVPacket pkt;
    321. ret = av_read_frame(overlay_fmt_ctx, &pkt);
    322. if (ret == AVERROR(EAGAIN)) {
    323. return 0;
    324. }
    325. if (ret < 0) {
    326. overlay_eof_reached = 1;
    327. ret = video_output_eof_packet("overlay_eof", overlay_fmt_ctx->streams[input_video_stream_idx], bufferoverlay_ctx);
    328. assert(ret >=0 );
    329. return ret;
    330. }
    331. if (pkt.stream_index != overlay_video_stream_idx) {
    332. av_free_packet(&pkt);
    333. return ret;
    334. }
    335. ret = avcodec_decode_video2(overlay_dec_ctx, mOverlayFrame, &got_frame, &pkt);
    336. if (ret < 0) {
    337. printf("Error decoding overlay video\n");
    338. }
    339. if (got_frame) {
    340. int64_t best_effort_timestamp = av_frame_get_best_effort_timestamp(mOverlayFrame);
    341. mOverlayFrame->pts = best_effort_timestamp;
    342. if (av_buffersrc_add_frame(bufferoverlay_ctx, mOverlayFrame, AV_BUFFERSRC_FLAG_PUSH) < 0) {
    343. av_log(NULL, AV_LOG_ERROR, "Error while feeding the audio filtergraph\n");
    344. return -1;
    345. }
    346. }
    347. return 0;
    348. }
    349. /**
    350. * output EOF packet to filter to flush
    351. */
    352. int video_output_eof_packet(const char* tag,
    353. AVStream* ist, AVFilterContext* ifilter)
    354. {
    355. int ret = 0;
    356. // alloc frame if NULL
    357. AVFrame* decoded_frame = avcodec_alloc_frame();
    358. AVPacket pkt;
    359. av_init_packet(&pkt);
    360. pkt.data = NULL;
    361. pkt.size = 0;
    362. int got_frame = 0;
    363. ret = avcodec_decode_video2(ist->codec, decoded_frame, &got_frame, &pkt);
    364. // EOF, assert got nothing and ret is 0.
    365. // TODO: here we still got frame, different to ffmpeg.
    366. assert(ret >= 0);
    367. // flush filter
    368. av_buffersrc_add_ref(ifilter, NULL, 0);
    369. printf("[%s] filter -> eof packet.\n", tag);
    370. return ret;
    371. }
    372. /**
    373. * save yuv420p frame [YUV]
    374. */
    375. void yuv420p_save(AVFrame *pFrame)
    376. {
    377. int i = 0;
    378. int width = pFrame->width, height = pFrame->height;
    379. int height_half = height / 2, width_half = width / 2;
    380. int y_wrap = pFrame->linesize[0];
    381. int u_wrap = pFrame->linesize[1];
    382. int v_wrap = pFrame->linesize[2];
    383. unsigned char *y_buf = pFrame->data[0];
    384. unsigned char *u_buf = pFrame->data[1];
    385. unsigned char *v_buf = pFrame->data[2];
    386. //save y
    387. for (i = 0; i < height; i++)
    388. fwrite(y_buf + i * y_wrap, 1, width, fp_yuv);
    389. //save u
    390. for (i = 0; i < height_half; i++)
    391. fwrite(u_buf + i * u_wrap, 1, width_half, fp_yuv);
    392. //save v
    393. for (i = 0; i < height_half; i++)
    394. fwrite(v_buf + i * v_wrap, 1, width_half, fp_yuv);
    395. fflush(fp_yuv);
    396. }

    ffmpeg 代码实现视频添加水印功能 - 图1