ffmpeg对应的版本号:

  configuration: --prefix=/home/zeng/share/ffmpeg/ffmpeg/build/ --enable-ffplaylibavutil      57. 24.101 / 57. 24.101libavcodec     59. 25.100 / 59. 25.100libavformat    59. 20.101 / 59. 20.101libavdevice    59.  6.100 / 59.  6.100libavfilter     8. 29.100 /  8. 29.100libswscale      6.  6.100 /  6.  6.100libswresample   4.  6.100 /  4.  6.100

下面是头文件、接口封装及相关的测试程序

#ifndef __ANDROID_AMIXER_H__
#define __ANDROID_AMIXER_H__ typedef enum {LogAmixer_None = 0,  //关闭日志输出LogAmixer_Urgent,    //必须打的LogAmixer_Fatal,     //致使级LogAmixer_Error,     //错误级LogAmixer_Warning,   //告警级LogAmixer_Info,      //业务级LogAmixer_Debug,     //调试级LogAmixer_Trace,     //跟踪级LogAmixer_Detail,    //详细级LogAmixer_Cnt
} LogAmixer;typedef enum {Amixer_SAMPLE_FMT_NONE = -1,Amixer_SAMPLE_FMT_U8,          ///< unsigned 8 bitsAmixer_SAMPLE_FMT_S16,         ///< signed 16 bitsAmixer_SAMPLE_FMT_S32,         ///< signed 32 bitsAmixer_SAMPLE_FMT_FLT,         ///< floatAmixer_SAMPLE_FMT_DBL,         ///< doubleAmixer_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planarAmixer_SAMPLE_FMT_S16P,        ///< signed 16 bits, planarAmixer_SAMPLE_FMT_S32P,        ///< signed 32 bits, planarAmixer_SAMPLE_FMT_FLTP,        ///< float, planarAmixer_SAMPLE_FMT_DBLP,        ///< double, planarAmixer_SAMPLE_FMT_S64,         ///< signed 64 bitsAmixer_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar
} AmixerSampleFormat;typedef int32_t (*AmixerPrint)(void *, const char *);//创建混音器句柄,主要是申请avfiltergraph对象
void *allocAmixerFilter();
//添加输出节点相关的信息,输出节点信息可以是任何有效参数范围内的值,不必与输入相同
int32_t addOutputToAmixerFilter(void *oObj, int32_t sampleRate,int32_t channels, AmixerSampleFormat format);
//添加输入节点相关的信息,输入节点信息可以是任何有效参数范围内的值,
//不必与输出相同,同样各个混音输入源参数信息可以不同,
//avfiltergraph内部会自动检索是否进行参数匹配检测,
//进而是否进行重采样等相关的自动处理
int32_t addInputToAmixerFilter(void *oObj, int32_t sampleRate, int32_t channels, AmixerSampleFormat format);
//从混音句柄中获取一帧数据
int32_t recvAmixerFilter(void *oObj, void *data, int32_t *size);
//向混音句柄中添加一帧待混音的数据,根据index(addInputToAmixerFilter调用顺序)索引输入源句柄
int32_t sendAmixerFilter(void *oObj, int32_t index, void *data, int32_t size);
//销毁整个混音句柄
void destoryAmixerFilter(void *oObj);
//初始化整个混音句柄
int32_t initAmixerFilter(void *oObj, int32_t outFrameMs);
//设置日志相关的便捷接口
int32_t setAmixerLog(void *priv, AmixerPrint print);#endif /*__ANDROID_AMIXER_H__*/
#include <unistd.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/avstring.h>#include "amixer.h"
/* #include <memwatch.h> *//*************************************************/
/**************LogPrintf**************************/
/*************************************************/
static void *gPriv = NULL;
static AmixerPrint gPrint;
static LogAmixer gLevel = LogAmixer_Info;static int AmixerLogPrintf(LogAmixer level,const char *file, const char *func,int line, const char *format, ...) {char logBuf[1024];va_list args;int funcLine        = 0;if (level > gLevel) return -1;snprintf (logBuf, sizeof(logBuf), "[%s][%s][%d]", file, func, line);funcLine = strlen(logBuf);/*va_list*/va_start(args, format);vsnprintf(&logBuf[funcLine], sizeof(logBuf) - funcLine, format, args);va_end(args);/*va_list*/if (gPrint) {return gPrint(gPriv, logBuf);}return -1;
}#define LogPrintf(level, ...)\AmixerLogPrintf(level, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__);#ifndef DEBUG0
#define DEBUG0(...)
#endif
#ifndef DEBUG1
#define DEBUG1(...)     LogPrintf(LogAmixer_Error, __VA_ARGS__);
#endif
#ifndef DEBUG2
#define DEBUG2(...)     LogPrintf(LogAmixer_Debug, __VA_ARGS__);
#endif#ifndef ERRP
#define ERRP(con, ret, flag, ...)               \if (con) {                              \DEBUG##flag(__VA_ARGS__)            \ret;                                \}
#endif#define MAX_INPUTS_NUM  (6)
#define WHITESPACES " \n\t\r"static enum AVSampleFormat getAmixerFormat(AmixerSampleFormat aformat) {enum AVSampleFormat format = AV_SAMPLE_FMT_NONE; switch (aformat) {case Amixer_SAMPLE_FMT_U8:format = AV_SAMPLE_FMT_U8;break;case Amixer_SAMPLE_FMT_S16:format = AV_SAMPLE_FMT_S16;break;case Amixer_SAMPLE_FMT_S32:format = AV_SAMPLE_FMT_S32;break;case Amixer_SAMPLE_FMT_FLT:format = AV_SAMPLE_FMT_FLT;break;case Amixer_SAMPLE_FMT_DBL:format = AV_SAMPLE_FMT_DBL;break;case Amixer_SAMPLE_FMT_U8P:format = AV_SAMPLE_FMT_U8P;break;case Amixer_SAMPLE_FMT_S16P:format = AV_SAMPLE_FMT_S16P;break;case Amixer_SAMPLE_FMT_S32P:format = AV_SAMPLE_FMT_S32P;break;case Amixer_SAMPLE_FMT_FLTP:format = AV_SAMPLE_FMT_FLTP;break;case Amixer_SAMPLE_FMT_DBLP:format = AV_SAMPLE_FMT_DBLP;break;case Amixer_SAMPLE_FMT_S64:format = AV_SAMPLE_FMT_S64;break;case Amixer_SAMPLE_FMT_S64P:format = AV_SAMPLE_FMT_S64P;break;default:break;}return format;
}int32_t setAmixerLog(void *priv, AmixerPrint print) {gPriv   = priv;gPrint  = print;return 0;
}typedef struct {void *handle;void *sink;void *source[MAX_INPUTS_NUM];int32_t inRef;int32_t outRef;int32_t sample_rate[MAX_INPUTS_NUM];enum AVSampleFormat format[MAX_INPUTS_NUM];AVChannelLayout ch_layout[MAX_INPUTS_NUM];int32_t  outRate;enum AVSampleFormat outFormat;AVChannelLayout outChLayout;
} AmixerFilter;void *allocAmixerFilter(void) {AmixerFilter *amixer                    = NULL;AVFilterGraph *graph                    = NULL;      graph = avfilter_graph_alloc();ERRP(graph == NULL, goto ERR0, 1, "get graph instance failure\n");amixer = (AmixerFilter *) av_mallocz (sizeof(*amixer));ERRP(amixer == NULL, goto ERR1, 1, "malloc AmixerFilter instance failure\n");amixer->handle      = graph;return amixer;
ERR1:avfilter_graph_free(&graph);
ERR0:return 0;
}int32_t addInputToAmixerFilter(void *oObj, int32_t sampleRate,int32_t channels, AmixerSampleFormat aformat) {int32_t status                  = -1;AmixerFilter *amixer            = NULL;AVFilterGraph *graph            = NULL;enum AVSampleFormat format      = AV_SAMPLE_FMT_NONE;const char *inName              = NULL;AVFilterContext *buffersrcCtx   = NULL;const AVFilter *abuffersrc      = NULL;AVChannelLayout ch_layout;char args[512];char buf[64];ERRP(1 != channels && 2 != channels, goto ERR0, 1, "set channes [%d] invalid, range to [1-2]\n", channels);ERRP(8000 != sampleRate && 16000 != sampleRate && 32000 != sampleRate && 44100 != sampleRate && 48000 != sampleRate && 96000 != sampleRate, goto ERR0, 1, "set sampleRate [%d] invalid, range to ""[8000-16000-32000-44100-48000-96000]\n", sampleRate);format = getAmixerFormat(aformat);ERRP(AV_SAMPLE_FMT_NONE == format, goto ERR0, 1, "get format [%d] failure\n", aformat);LogPrintf (LogAmixer_Info, "format:%d\n", format);amixer  = (AmixerFilter *)oObj;if (amixer) {ERRP(amixer->inRef >= MAX_INPUTS_NUM || amixer->inRef < 0, goto ERR0, 1, "set inRef [%d] to max, range(0-%d]\n", amixer->inRef, MAX_INPUTS_NUM);graph   = (AVFilterGraph *)amixer->handle;if (graph) {snprintf (args, sizeof(args) - 1, "input%d", amixer->inRef);inName = av_strdup((const char *)args);ERRP(inName == NULL, goto ERR0, 1, "parse in[%s] failure\n", args);av_channel_layout_default(&ch_layout, channels);av_channel_layout_describe(&ch_layout, buf, sizeof(buf));snprintf (args, sizeof(args) - 1, "sample_rate=%d:sample_fmt=%s:channel_layout=%s", sampleRate, av_get_sample_fmt_name(format), buf);LogPrintf (LogAmixer_Info, "args:%s\n", args);abuffersrc = avfilter_get_by_name("abuffer");ERRP(abuffersrc == NULL, goto ERR1, 1, "input abuffer get abuffer failure\n");status = avfilter_graph_create_filter(&buffersrcCtx, abuffersrc, inName, args, NULL, graph);ERRP(status < 0, goto ERR1, 1, "create source filter %s failure\n", inName);amixer->sample_rate[amixer->inRef]  = sampleRate;amixer->ch_layout[amixer->inRef]    = ch_layout;amixer->format[amixer->inRef]       = format;amixer->source[amixer->inRef++]     = buffersrcCtx;}}return 0;
ERR1:if (inName) av_free((void *)inName);if (buffersrcCtx) avfilter_free(buffersrcCtx);
ERR0:return -1;
}int32_t addOutputToAmixerFilter(void *oObj, int32_t sampleRate,int32_t channels, AmixerSampleFormat aformat) {int32_t status                  = -1;AmixerFilter *amixer            = NULL;AVFilterGraph *graph            = NULL;enum AVSampleFormat format      = AV_SAMPLE_FMT_NONE;const char *inName              = NULL;AVFilterContext *buffersinkCtx  = NULL;const AVFilter *abuffersink     = NULL;AVChannelLayout ch_layout;char args[512];char buf[64];ERRP(1 != channels && 2 != channels, goto ERR0, 1, "set channes [%d] invalid, range to [1-2]\n", channels);ERRP(8000 != sampleRate && 16000 != sampleRate && 32000 != sampleRate && 44100 != sampleRate && 48000 != sampleRate && 96000 != sampleRate, goto ERR0, 1, "set sampleRate [%d] invalid, range to ""[8000-16000-32000-44100-48000-96000]\n", sampleRate);format = getAmixerFormat(aformat);ERRP(AV_SAMPLE_FMT_NONE == format, goto ERR0, 1, "get format [%d] failure\n", aformat);LogPrintf (LogAmixer_Info, "format:%d\n", format);amixer  = (AmixerFilter *)oObj;if (amixer) {//只允许一个输出ERRP(amixer->outRef >= 1 || amixer->outRef < 0, goto ERR0, 1, "set amixer->outRef [%d] to max, range(0-%d]\n", amixer->outRef, MAX_INPUTS_NUM);graph   = (AVFilterGraph *)amixer->handle;if (graph) {inName = av_strdup("output");ERRP(inName == NULL, goto ERR0, 1, "parse output failure\n");abuffersink = avfilter_get_by_name("abuffersink");ERRP(abuffersink == NULL, goto ERR1, 1, "input abuffer get abuffer failure\n");status = avfilter_graph_create_filter(&buffersinkCtx, abuffersink, inName, NULL, NULL, graph);ERRP(status < 0, goto ERR1, 1, "create sink filter %s failure\n", inName);status = av_opt_set_bin(buffersinkCtx, "sample_fmts",(uint8_t*)&format, sizeof(format),AV_OPT_SEARCH_CHILDREN);ERRP (status < 0, goto ERR1, 1, "Cannot set output sample format\n");av_channel_layout_default(&ch_layout, channels);av_channel_layout_describe(&ch_layout, buf, sizeof(buf));status = av_opt_set(buffersinkCtx, "ch_layouts", buf, AV_OPT_SEARCH_CHILDREN);ERRP (status < 0, goto ERR1, 1, "Cannot set output sample format\n");status = av_opt_set_bin(buffersinkCtx, "sample_rates",(uint8_t*)&sampleRate, sizeof(sampleRate), AV_OPT_SEARCH_CHILDREN);ERRP (status < 0, goto ERR1, 1, "Cannot set output sample rate\n");amixer->sink        = buffersinkCtx;amixer->outRate     = sampleRate;amixer->outChLayout = ch_layout;amixer->outFormat   = format;amixer->outRef      = 1;}}return 0;
ERR1:if (inName) av_free((void *)inName);if (buffersinkCtx) avfilter_free(buffersinkCtx);
ERR0:return -1;
}/* 参数1:混音过滤器字符串格式化 * 参数2:混音输入源个数,必要和参数1里面的输入源对应上* 参数3:采样率* 参数4:通道数* 参数5:采样位数 /16bit, 32bit/*/
int32_t initAmixerFilter(void *oObj, int32_t outFrameMs)
{int32_t status                          = -1;int32_t index                           = 0;enum AVSampleFormat format              = AV_SAMPLE_FMT_NONE;AmixerFilter *amixer                    = NULL;AVFilterGraph *graph                    = NULL;      const char *inName[MAX_INPUTS_NUM]      = {NULL};const char *outName                     = NULL;AVFilterContext *buffersinkCtx          = NULL;AVFilterInOut *input                    = NULL;AVFilterInOut *output[MAX_INPUTS_NUM]   = {NULL};const AVFilter *buffersink              = NULL;AVFilterContext *buffersrcCtx[MAX_INPUTS_NUM]   = {NULL};const AVFilter *abuffersrc[MAX_INPUTS_NUM]      = {NULL};AVChannelLayout ch_layout;char args[512];char buf[64];args[0] = '\0';amixer = (AmixerFilter *)oObj;if (amixer) {ERRP(amixer->inRef > MAX_INPUTS_NUM || amixer->inRef <= 0, goto ERR0, 1, "set amixer->inRef [%d] to max, range(0-%d]\n", amixer->inRef, MAX_INPUTS_NUM);ERRP(amixer->outRef > 1 || amixer->outRef <= 0, goto ERR0, 1, "set amixer->outRef [%d] to max, range(0-%d]\n", amixer->outRef, MAX_INPUTS_NUM);graph = amixer->handle;if (graph) {for (index = 0; index < amixer->inRef; index++) {output[index]           = avfilter_inout_alloc();ERRP(output[index] == NULL, goto ERR1, 1, "alloc [%d] inout failrue\n", index);buffersrcCtx[index] = (AVFilterContext *)amixer->source[index];inName[index]       = av_strdup(buffersrcCtx[index]->name);snprintf (buf, sizeof(buf) - 1, "[%s]", inName[index]);strcat(args, buf);}for (index = 0; index < amixer->inRef; index++) {output[index]->name         = (char *)inName[index];output[index]->filter_ctx   = buffersrcCtx[index];output[index]->pad_idx      = 0;output[index]->next         = (index == amixer->inRef - 1) ? NULL : output[index + 1];}buffersinkCtx       = (AVFilterContext *)amixer->sink;outName             = av_strdup(buffersinkCtx->name);input               = avfilter_inout_alloc();ERRP(input == NULL, goto ERR1, 1, "alloc input inout failrue\n", index);input->name         = (char *)outName;input->filter_ctx   = buffersinkCtx;input->pad_idx      = 0;input->next         = NULL;snprintf (buf, sizeof(buf) - 1, "amix=inputs=%d[%s]", amixer->inRef, outName);strcat(args, buf);LogPrintf (LogAmixer_Info, "filters:%s\n", args);status = avfilter_graph_parse_ptr(graph, args, &input, &output[0], NULL);ERRP(status < 0, goto ERR1, 1, "parse ptr(%s) failure\n", args);status = avfilter_graph_config(graph, NULL);ERRP(status < 0, goto ERR1, 1, "config ptr(%s) failure\n", args);av_buffersink_set_frame_size(buffersinkCtx, outFrameMs * amixer->outRate / 1000);}}return 0;
ERR1:if (input) avfilter_inout_free(&input);for (index = 0; index < amixer->inRef; index++) {if (output[index]) {avfilter_inout_free(&output[index]);}}if (outName) free((void *)outName);for (index = 0; index < amixer->inRef; index++) {if (inName[index]) free((void *)inName[index]);}
ERR0:return -1;
}void destoryAmixerFilter(void *oObj) {AVFilterGraph *graph = NULL;AmixerFilter *amixer = (AmixerFilter *)oObj;if (amixer) {graph = (AVFilterGraph *)amixer->handle;if (graph) {avfilter_graph_free(&graph);}av_free(amixer);}
}int32_t sendAmixerFilter(void *oObj, int32_t index, void *data, int32_t size) {int32_t status          = -1;AVFrame *frame          = NULL;AVFilterContext *inCtx  = NULL;AmixerFilter *amixer    = (AmixerFilter *)oObj;ERRP(index < 0 || index > MAX_INPUTS_NUM, return -1, 0);ERRP(oObj == NULL, return -1, 0);ERRP(data == NULL, return -1, 0);frame = av_frame_alloc();ERRP(frame == NULL, goto ERR0, 1, "av_frame_alloc failrue\n");if (amixer) {inCtx   = (AVFilterContext *)amixer->source[index];if (inCtx) {frame->sample_rate      = amixer->sample_rate[index];frame->ch_layout        = amixer->ch_layout[index];frame->format           = amixer->format[index];frame->nb_samples       = size / (av_get_bytes_per_sample(amixer->format[index]) * amixer->ch_layout[index].nb_channels);status = av_frame_get_buffer(frame, 0);ERRP(status < 0, goto ERR1, 1, "av_frame_get_buffer failure\n");memcpy(frame->data[0], data, size);status = av_buffersrc_add_frame_flags(inCtx, frame, 0);ERRP(status < 0, goto ERR1, 1, "av_buffersrc_add_frame_flags %d", status);}}ERR1:av_frame_free(&frame);
ERR0:return status;
}int32_t recvAmixerFilter(void *oObj, void *data, int32_t *size) {int32_t status          = -1;AVFrame *frame          = NULL;AVFilterContext *outCtx = NULL;AmixerFilter *amixer    = (AmixerFilter *)oObj;ERRP(oObj == NULL, return -1, 0);ERRP(data == NULL, return -1, 0);frame = av_frame_alloc();ERRP(frame == NULL, goto ERR0, 1, "av_frame_alloc failrue\n");if (amixer) {outCtx   = (AVFilterContext *)amixer->sink;if (outCtx) {status = av_buffersink_get_frame_flags(outCtx, frame, 0);ERRP(status < 0, goto ERR1, 1, "av_buffersink_get_frame_flags:%d", status);*size = frame->nb_samples * av_get_bytes_per_sample(frame->format) * frame->ch_layout.nb_channels;memcpy(data, frame->data[0], *size);}}ERR1:av_frame_free(&frame);
ERR0:return status;
}#ifdef TEST_AMIXERint32_t print(void *priv, const char *strings) {printf ("%s", strings);return 0;
}int main(int args, char *argv[]) {int32_t ret         = -1;void *pObj          = NULL;char *filter_descr  = "[in0][in1]amix=inputs=2[out]";int16_t buffer[1920];if (args != 4) {printf ("args == 4 ==> ./amixer in.pcm in1.pcm out.pcm\n");return -1;}FILE *fpIn0 = fopen(argv[1], "r");FILE *fpIn1 = fopen(argv[2], "r");FILE *fpOut = fopen(argv[3], "w+");setAmixerLog(NULL, print);pObj = allocAmixerFilter();if (pObj) {addInputToAmixerFilter(pObj, 48000, 1, Amixer_SAMPLE_FMT_S16);addInputToAmixerFilter(pObj, 48000, 1, Amixer_SAMPLE_FMT_S16);addOutputToAmixerFilter(pObj, 48000, 1, Amixer_SAMPLE_FMT_S16);initAmixerFilter(pObj, 10);while (1) {int size = fread(buffer, 1, sizeof(buffer), fpIn0);if (size != sizeof(buffer)) break;ret = sendAmixerFilter(pObj, 0, buffer, sizeof(buffer));if (ret < 0) break;size = fread(buffer, 1, sizeof(buffer), fpIn1);if (size != sizeof(buffer)) break;ret = sendAmixerFilter(pObj, 1, buffer, sizeof(buffer));if (ret < 0) break;ret = recvAmixerFilter(pObj, buffer, &size);if (ret < 0) break;fwrite(buffer, 1, size, fpOut);}}fclose(fpIn0);fclose(fpIn1);fclose(fpOut);destoryAmixerFilter(pObj);return 0;
}
#endif

ffmpeg avfilter-avfiltergraph之混音相关推荐

  1. ffmpeg pcm混音

    视频会议中经常需要处理的场景有多路音频混音,那么混音有很多种算法有比较主流的有归一权重.叠加均值.平均权重等方法:如果公司要开发生产级别的音频混合要的算法可能会更加多,可以找算法公司购买. ffmpe ...

  2. ffmpeg进行混音,将两路音频pcm数据合成一路输出

    ffmpeg进行混音,将两路音频pcm数据合成一路输出 audiomixer.h #ifndef AUDIOMIXER_H #define AUDIOMIXER_H#include <map&g ...

  3. FFmpeg 混音学习【一】FFmpeg aac音频混流学习及问题记录

    主要学习的是ffmpeg官方demo里的doc/examples/filtering_audio.c ffmpeg混流的主要流程 初始化filter 读取aac数据,解码后将数据压入filter bu ...

  4. ffmpeg 本地麦克风声音和系统声音混音后,再混合本地桌面成最终的mp4文件-修正

    之前本人写过一篇博客: ffmpeg 本地麦克风声音和系统声音混音后,再混合本地桌面成最终的mp4文件 但是存在着下面两个问题: 1.系统声音和麦克风对应的设备的采样率不一样,没有进行重采样,比如系统 ...

  5. ffmpeg4教程10:avfilter混音处理

    基于vs2017 vc++  ffmpeg4.0.2下测试 ffmpeg 环境配置请百度(vs2017 ffmpeg ) 主要是先将音频avframe采集到队列或链表里,再通过 av_buffersr ...

  6. android 混音 源码,FFmpegAndroid android 端基于 FFmpeg 实现音频剪切、拼接、转码、混音、编解码;视频剪切、水印、截图、转码、编 @codeKK c开源站...

    android 端基于 FFmpeg 库的使用 添加编译 ffmpeg.shine.mp3lame.x264 源码的参考脚本 目前音视频相关处理: 音频剪切.拼接 音频混音 音频转码 音视频合成 音频 ...

  7. ffmpeg filter amix混音实现

    一.实现思路 ffmpeg的滤波filter有amix这个混音器,可以借助它来做音频的多路混音.首先我们需要编译ffmpeg并安装它,可以具备编码功能,考虑可以加mp3或者aac编码库进来,最简单的方 ...

  8. 【Android FFMPEG 开发】Android 中使用 FFMPEG 对 MP3 文件进行混音操作

    文章目录 一.前置操作 ( 移植 FFMPEG ) 二.FFMPEG 混音命令 三.Android FFMPEG 混音源代码完整示例 四.博客源码 一.前置操作 ( 移植 FFMPEG ) 参考 [A ...

  9. FFMPEG 实现混音,加水印,加文字,模糊水印任意滤镜组合

    一共15种组合一下搞定:先伪代码没逻辑错误,然后就撸正式代码,后面测试就有点小顺利了 伪代码: 根据参数构造ffmpeg参数命令 构造元素视频方面有水印,文字,去水印:音频方面有混音一个 构造顺序: ...

最新文章

  1. 离奇的梦境,能够防范大脑过拟合
  2. 开发日记-20190620 关键词 今日回顾
  3. SpringMVC总结三:请求Controller返回视图类型以及请求方式、参数介绍
  4. ITK:使用基于多尺寸Hessian的量度来分割血管
  5. VTK:可视化算法之StreamlinesWithLineWidget
  6. C++Quick sort快速排序的实现算法之一(附完整源码)
  7. 她被“誉为”中科院最美女院士,52岁依然貌美如花?气质不输女星
  8. 数据结构-哈希与映射
  9. bootstrap插件(对话框)bootbox参数和自定义弹出框宽度设置
  10. nginx开发从入门到精通【淘宝核心系统服务器】
  11. SQLite数据类型详解
  12. java随机点名器的代码_巧用Excel制作随机点名器,简单易学,快来尝试吧
  13. 40 多套 Java 完整实战项目,各个精品!
  14. 数据库sql中S P J SPJ 表的创建
  15. SystemUI原生信号塔替换为五格信号塔
  16. iP网络广播系统服务器搭建,IP网络智能公共广播系统V2.0
  17. 对SPU、SKU的一点理解
  18. 【Unity】UGUI控件大小适配父容器
  19. Solaris加载ISO虚拟光驱文件
  20. 三极管工作原理--我见过最通俗讲法

热门文章

  1. java dao类 反射_java反射机制编写简单万能DAO类
  2. php三极管驱动蜂鸣器计算,基于蜂鸣器的开关三极管使用误区详解
  3. sin(x)表面下潜藏的一些不为人知的秘密,你想知道吗?
  4. elementui 表单自动校验
  5. Java和MySQL编写的简单手机销售管理系统
  6. QQ网页密码加密解析
  7. RMSE:(均方根误差)、MSE:(均方误差)、RSS(残差平方和),RSE(残差的标准误差),R^2.
  8. win10家庭版升级专业版的两种方法和密钥
  9. python第一个代码_L1.开始第一个Python代码
  10. Android播放透明视频