/usr/local/lib/pkgconfig $FFMPEG_ROOT/configure --target-os=linux \ --prefix=$PREFIX \ --disable-encoders \ --disable-decoders \ --disable-muxers \ --disable-demuxers \ --disable-parsers \ --disable-bsfs \ --disable-protocols \ --disable-devices \ --disable-avdevice \ --disable-zlib \ --disable-bzlib \ --enable-cross-compile \ --enable-runtime-cpudetect \ --pkg-config-flags="--static" \ --disable-asm \ --arch=arm \ --enable-armv5te \ --cc=$PREBUILT/bin/arm-linux-androideabi-gcc \ --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \ --disable-stripping \ --nm=$PREBUILT/bin/arm-linux-androideabi-nm \ --sysroot=$PLATFORM \ --enable-nonfree \ --enable-version3 \ --enable-gpl \ --disable-doc \ --disable-ffplay \ --disable-ffserver \ --disable-ffprobe \ --enable-avcodec \ --enable-avformat \ --enable-avutil \ --enable-avfilter \ --enable-avresample \ --enable-swresample \ --enable-swscale \ --enable-postproc \ --enable-libx264 \ --enable-encoder=libx264 \ --enable-decoder=h264 \ --enable-hwaccels \ --enable-memalign-hack \ --disable-debug \ --enable-pthreads \ --disable-filters \ --enable-libfreetype \ --enable-filter=drawbox \ --enable-filter=drawtext \ --enable-avisynth \ --enable-iconv \ --extra-cflags="-Os -s -I$X264_ROOT -I$NDK/sysroot/include -I$PREFIX/include/freetype -I$PREFIX/include/ -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -mfpu=neon -marm -march=armv7-a -mvectorize-with-neon-quad" \ --extra-ldflags="-L$ELIB -L$NDK/sysroot/lib -L$NDK/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a -L$PREFIX/lib" \ --extra-libs="-lfreetype2-static -lstdc++ -lgnustl_static -fexceptions -lsupc++ -llog "
然后添加水印过程中出现水波纹的现象,主要原因是给定的width和height和实际的bitmap不匹配产生。
如下为doubango下编码前添加水印的部分代码:
# include <libavfilter/avfiltergraph.h> # include <libavfilter/avfilter.h> # include <libavfilter/avcodec.h> # include <libavfilter/buffersink.h> # include <libavfilter/buffersrc.h> # include <libavutil/avutil.h> # include <libavutil/imgutils.h> static AVFilterContext* buffersink_ctx = NULL; static AVFilterContext* buffersrc_ctx = NULL; static AVFilterGraph* filter_graph = NULL; static AVFrame* frame_in = NULL; static AVFrame* frame_out = NULL; static int isInited; static int origin_in_width = 480; static int origin_in_height = 320; static char last_wartmark_str[125] = "\0"; static char filters_descr[256] = "\0"; static int init_filters(tmedia_codec_t* self) { tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; if (!tmedia_defaults_get_use_water_mark_func_flg()){ return -1; } if (tmedia_defaults_get_water_mark_strvalue() == tsk_null){ TSK_DEBUG_ERROR("tmedia_defaults_get_water_mark_strvalue() is null\n"); tmedia_defaults_set_use_water_mark_func_flg(tsk_false, tmedia_defaults_get_water_mark_position_x(), tmedia_defaults_get_water_mark_position_y()); return -1; } if (strlen(last_wartmark_str) == 0){ strncpy(last_wartmark_str, tmedia_defaults_get_water_mark_strvalue(), sizeof(last_wartmark_str) - 1); last_wartmark_str[124] = '\0'; } if ((tsk_strcmp(last_wartmark_str, tmedia_defaults_get_water_mark_strvalue()) != 0)){ tdav_codec_h264_deinit_filters(); isInited = 0;//refresh filters. } strncpy(last_wartmark_str, tmedia_defaults_get_water_mark_strvalue(), sizeof(last_wartmark_str)); //TSK_DEBUG_INFO("init filters ,Picture size: %u ** %u", h264->encoder.context->width, h264->encoder.context->height); if(!self){ TSK_DEBUG_ERROR("self is null\n"); return -1; } int in_width=h264->encoder.context->width; int in_height=h264->encoder.context->height; int format = PIX_FMT_YUV420P; if(!in_width || !in_height) { TSK_DEBUG_ERROR("in_width\in_height is null\n"); return -1; } if( in_width != origin_in_width || in_height != origin_in_height){ tdav_codec_h264_deinit_filters(); isInited = 0; } if(isInited){ TSK_DEBUG_INFO("here init graphfilter ok.\n"); return -1; } if(filter_graph) { avfilter_graph_free(&filter_graph); } //static char *filters_descr = "drawbox=x=100:y=100:w=50:h=50:color=pink@0.5"; //static char *filters_descr = "drawtext=fontfile=/sdcard/arialbd.ttf:fontsize=30:text=\'6102124695\':x=100:y=x/dar:fontcolor=red@0.5:shadowy=2"; //static char *filters_descr = "drawtext=fontfile=/sdcard/arialbd.ttf:fontsize=30:text=\'6102124695\':x=100:y=x/dar"; //static char *filters_descr = "drawtext=fontsize=30:text=\'6102124695\':fontcolor=red"; char *font_color = "red"; switch(tmedia_defaults_get_water_font_color()){ case 0: //red font_color = "red"; break; case 1://green font_color = "green"; break; case 2://blue font_color = "blue"; break; case 3://black font_color = "black"; break; case 4://yello font_color = "yello"; break; case 5://oreage font_color = "oreage"; break; case 6://white font_color = "White"; break; default: break; }; if (tmedia_defaults_get_water_font_path() == tsk_null){ snprintf(filters_descr, sizeof(filters_descr), "drawtext=fontfile=/sdcard/arialbd.ttf:fontsize=%d:text=%s:x=%d:y=%d:fontcolor=%s@0.6:borderw=2:bordercolor=black@0.6", tmedia_defaults_get_water_font_size(), tmedia_defaults_get_water_mark_strvalue(), tmedia_defaults_get_water_mark_position_x(), tmedia_defaults_get_water_mark_position_y(), font_color); }else{ snprintf(filters_descr, sizeof(filters_descr), "drawtext=fontfile=%s:fontsize=%d:text=%s:x=%d:y=%d:fontcolor=%s@0.6:borderw=2:bordercolor=black@0.6", tmedia_defaults_get_water_font_path(), tmedia_defaults_get_water_font_size(), tmedia_defaults_get_water_mark_strvalue(), tmedia_defaults_get_water_mark_position_x(), tmedia_defaults_get_water_mark_position_y(), font_color); } avfilter_register_all(); char args[512]; int ret = 0; AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("buffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); filter_graph = avfilter_graph_alloc(); if (!outputs || !inputs || !filter_graph) { ret = AVERROR(ENOMEM); goto end; } /* buffer video source: the decoded frames from the decoder will be inserted here. */ snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", in_width, in_height, PIX_FMT_YUV420P, 1, tmedia_defaults_get_video_fps(), 1, 1); ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph); if (ret < 0) { TSK_DEBUG_ERROR("Cannot create buffer source, %d, \n", ret); av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); goto end; } /* buffer video sink: to terminate the filter chain. */ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph); if (ret < 0) { TSK_DEBUG_ERROR("Cannot create buffer sink, %d, \n", ret); av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); goto end; } ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { TSK_DEBUG_ERROR("Cannot set output pixel format, %d, \n", ret); av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } /* * Set the endpoints for the filter graph. The filter_graph will * be linked to the graph described by filters_descr. */ /* * The buffer source output must be connected to the input pad of * the first filter described by filters_descr; since the first * filter input label is not specified, it is set to "in" by * default. */ outputs->name = av_strdup("in"); outputs->filter_ctx = buffersrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; /* * The buffer sink input must be connected to the output pad of * the last filter described by filters_descr; since the last * filter output label is not specified, it is set to "out" by * default. */ inputs->name = av_strdup("out"); inputs->filter_ctx = buffersink_ctx; inputs->pad_idx = 0; inputs->next = NULL; if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0){ TSK_DEBUG_ERROR("avfilter_graph_parse_ptr failed, ret:%d.\n", ret); goto end; } if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0){ TSK_DEBUG_ERROR("avfilter_graph_config failed, ret:%d.\n", ret); goto end; } if (ret == 0){ frame_in = av_frame_alloc(); unsigned char* frame_buffer_in = (unsigned char*)av_malloc(av_image_get_buffer_size(format,in_width, in_height, 1)); av_image_fill_arrays(frame_in->data, frame_in->linesize, frame_buffer_in, format,in_width, in_height, 1); frame_out = av_frame_alloc(); /* unsigned char* frame_buffer_out = (unsigned char*)av_malloc(av_image_get_buffer_size(format,in_width, in_height, 1)); av_image_fill_arrays(frame_out->data, frame_out->linesize, frame_buffer_out,format,in_width, in_height, 1); */ } TSK_DEBUG_INFO("init graphfilter ok.\n"); isInited = 1; end: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; } // static int tdav_codec_h264_deinit_filters(){ if (!isInited){ return; } isInited = 0; if (frame_in != NULL){ av_frame_free(&frame_in); } if (frame_out != NULL){ av_frame_free(&frame_out); } if (buffersink_ctx != NULL){ avfilter_free(buffersink_ctx); buffersink_ctx = NULL; } if (buffersrc_ctx != NULL){ avfilter_free(buffersrc_ctx); buffersrc_ctx = NULL; } if (filter_graph != NULL){ //avfilter_graph_free(&filter_graph); } last_wartmark_str[0] = '\0'; } // static int tdav_codec_h264_add_water_marker(tmedia_codec_t* self, AVFrame* frame_src, const unsigned char* in_data){ //TSK_DEBUG_ERROR("enter tdav_codec_h264_add_water_marker\n"); if (!tmedia_defaults_get_use_water_mark_func_flg()){ return -1; } if(!isInited) { TSK_DEBUG_INFO(" graphfilter not inited.\n"); return -1; } int ret; //AVFrame* frame_out = NULL; tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; //TSK_DEBUG_INFO("Picture size: %u ** %u", h264->encoder.context->width, h264->encoder.context->height); if(!self){ TSK_DEBUG_ERROR("self is null\n"); return -1; } int in_width=h264->encoder.context->width; int in_height=h264->encoder.context->height; int format = PIX_FMT_YUV420P; if(!in_width || !in_height) { TSK_DEBUG_ERROR("in_width\in_height is null\n"); return -1; } //init frame out //frame_out = av_frame_alloc(); /* unsigned char* frame_buffer_out = (unsigned char*)av_malloc(av_image_get_buffer_size(format,in_width, in_height, 1)); av_image_fill_arrays(frame_out->data, frame_out->linesize, frame_buffer_out,format,in_width, in_height, 1); */ if (!frame_in || !frame_out) { TSK_DEBUG_ERROR("Could not allocate frame\n"); return -1; } frame_in->width=in_width; frame_in->height=in_height; frame_in->format=format; // TSK_DEBUG_ERROR("frame_in width is %d, height is %d \n",frame_in->width, frame_in->height ); //copy data //0. copy data to frame_in memcpy(frame_in->data[0], frame_src->data[0], in_width*in_height); memcpy(frame_in->data[1], frame_src->data[1], in_width*in_height*1/4); memcpy(frame_in->data[2], frame_src->data[2], in_width*in_height*1/4); // 1.add frame to filtergraph // ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame_in, 0); ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame_in, AV_BUFFERSRC_FLAG_KEEP_REF); if(ret < 0) { TSK_DEBUG_ERROR("Cannot add frame to graph \n"); TSK_DEBUG_ERROR("Cannot add frame to graph,ret is %d \n",ret); goto end; } // 2.pull filtered pictures from the filtergraph ret = av_buffersink_get_frame(buffersink_ctx, frame_out); if(ret < 0) { TSK_DEBUG_ERROR("Cannot get frame from graph \n"); TSK_DEBUG_ERROR("Cannot get frame from graph,ret is %d \n",ret); goto end; } //3. copy data to frame_src //ret = av_frame_copy(frame_src, frame_out); //memcpy(frame_src->data[0], frame_out->data[0], in_width*in_height); //memcpy(frame_src->data[1], frame_out->data[1], in_width*in_height*1/4); //memcpy(frame_src->data[2], frame_out->data[2], in_width*in_height*1/4); av_image_copy(frame_src->data, frame_src->linesize, frame_out->data, frame_out->linesize, PIX_FMT_YUV420P, in_width, in_height); end: //av_frame_free(&frame_out); av_frame_unref(frame_out); return ret; } //编码前先将bitmap的yuv数据添加水印 #if ADD_WATER_MARKER //tdav_codec_h264_init_filters(self); init_filters(self); tdav_codec_h264_add_water_marker(self, h264->encoder.picture, (const unsigned char*)in_data); //tdav_codec_h264_add_water_marker2((const unsigned char*)in_data, in_size); #endif
ffmpeg编码参数优化:
if((ret = av_opt_set_double(self->encoder.context->priv_data, "crf", (double)30, 0))){ TSK_DEBUG_ERROR("Failed to set x264 crf 28.0"); return; } //ultrafast veryfast superfast if((ret = av_opt_set(self->encoder.context->priv_data, "preset", "superfast", 0))){ TSK_DEBUG_ERROR("Failed to set x264 preset to veryfast"); }
encoder.context->rtp_payload_size = H264_RTP_PAYLOAD_SIZE;//H264_RTP_PAYLOAD_SIZE大小为1300if((ret = av_opt_set_int(self->encoder.context->priv_data, "slice-max-size", H264_RTP_PAYLOAD_SIZE, 0))){ TSK_DEBUG_ERROR("Failed to set x264 slice-max-size to %d", H264_RTP_PAYLOAD_SIZE);}
-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com
本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com