Linux应用程序--exec与system


文章摘要:
本文描述了基于Linux应用程序进程控制中的fork,wait,exec,system等函数的详细说明及应用场景。

execl/execlp/execle/execv/execvp/execve

l - 表示ArgList,需要将参数放入argv数组列表中传递;
v - 表示将参数拆分为单独项传递,需要以NULL做为最后一个参数;

p - 表示从环境变量PATH指明的路径中,寻找对应的可执行文件,不需要指明绝对路径;
e - 表示可以将指定环境变量参数传入(包括但不限于PATH)。

示例:

execl("/bin/ls", "ls", "-l", "/etc", NULL); 
execlp("ls", "ls", "-l", "/etc", NULL);

char* args[] = {"ls", "-l", "/etc", NULL};
execv("/bin/ls", args); 
execvp("ls",args);  


char* envs[] = {"USER=unkonwn", "PATH=/bin", NULL};

execle("ls", "ls", "-l", "/etc", NULL, envs);
execve("ls", argv, envs);

注意事项: 第1个参数是可执行文件名。

- 阅读全文 -

ffmpeg编程接口--音频解码


文章描述: 本文主要描述了通过ffmpeg接口对音频进行编解码的例程,及主要函数详细说明。
操作系统: Debian8

/* 
 * 功能描述: 打开指定音频文件,转换成PCM数据格式,并保存至文件中
 *           支持多种格式文件输入mp3,m4a等
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libavcodec/avcodec.h>       // 解码器
#include <libavformat/avformat.h>     // 封装格式
#include <libswresample/swresample.h> // 重采样格式转换

int main(int argc, char **argv)
{
  // 1.注册组件 -----------------------------------------------------
  av_register_all();
  // 封装格式上下文
  AVFormatContext *pFormatCtx = avformat_alloc_context();
  // 2.打开输入音频文件 ---------------------------------------------
  if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
  {
    printf("打开输入音频文件失败.\r\n");
    return -1;
  }
  // 3.获取音频信息 -------------------------------------------------
  if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
  {
    printf("获取音频信息失败.\r\n");
    return -2;
  }
  // 音频解码: 找到对应的AVStream所在的pFormatCtx->streams的索引位置
  int i;
  int audio_stream_idx = -1;
  for (i = 0; i < pFormatCtx->nb_streams; i++)
  {
    // 根据类型判断是否是音频流
    if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
    {
      printf("查找到音频流\r\n");
      audio_stream_idx = i;
    }
    // 根据类型判断是否是视频流
    else if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
    {
      printf("查找到视频流\r\n");
    }
    else
    {
      printf("未知的编码类型: %d\r\n", pFormatCtx->streams[i]->codec->codec_type);
    }  
  }

  // 4.获取解码器 ---------------------------------------------------
  // 通过stream获取解码器上下文
  AVCodecContext *pCodeCtx = pFormatCtx->streams[audio_stream_idx]->codec;
  // 通过编解码id获取解码器
  AVCodec *pCodec = avcodec_find_decoder(pCodeCtx->codec_id);
  if (pCodec == NULL)
  {
    printf("未找到对应解码器.\r\n");
    return -3;
  }

  // 5.打开解码器 ---------------------------------------------------
  if (avcodec_open2(pCodeCtx, pCodec, NULL) < 0)
  {
    printf("解码器无法打开");
    return -4;
  }

  // 申请数据内存:编码数据(原始数据)
  AVPacket *packet = av_malloc(sizeof(AVPacket));
  // 申请数据内存:解码数据
  AVFrame *frame = av_frame_alloc();

  // 设置解码器选项--------------------------------------------------
  SwrContext *swrCtx = swr_alloc();

  // 输出的采样格式 16bit PCM
  enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
  // 输出的采样率
  int out_sample_rate = 44100;
  // 输出的声道布局
  uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO; // (立体声)

  swr_alloc_set_opts(swrCtx,
                     out_ch_layout,            // 输出的声道布局
                     out_sample_fmt,           // 输出的采样格式 16bit PCM
                     out_sample_rate,          // 输出的采样率
                     pCodeCtx->channel_layout, // 输入的声道布局
                     pCodeCtx->sample_fmt,     // 输入的采样格式
                     pCodeCtx->sample_rate,    // 输入的采样率
                     0,                        // 日志偏移 log_offset
                     NULL);                    // 日志指针 log_ctx

  swr_init(swrCtx); // 初始化解码器
  // ----------------------------------------------------------------
  // 通过声道布局获取声道数
  int out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
  int ret;
  int got_frame;

  // 申请单个采样点PCM数据所需要的内存(2*2*44100)
  uint8_t *out_buffer = (uint8_t *)av_malloc(2 * 2 * 44100);
  if (out_buffer == NULL)
  {
    exit(1);
  }
  FILE *fp_pcm = fopen("out.pcm", "wb");

  // 6.一帧一帧读取压缩的音频数据AVPacket
  while (av_read_frame(pFormatCtx, packet) >= 0)
  {
    if (packet->stream_index == audio_stream_idx)
    {
      // 解码:AVPacket->AVFrame
      ret = avcodec_decode_audio4(pCodeCtx, frame, &got_frame, packet);
      if (ret < 0)
      {
        printf("解码出错.\r\n");
      }

      // 获取有效帧
      if (got_frame)
      {
        // 由于解码器输出的数据与PCM播放的格式不一致,所以需要转换一下
        swr_convert(swrCtx,
                    &out_buffer,                   // 输出数据缓冲区
                    2 * 2 * 44100,                 // 输出缓冲区大小
                    (const uint8_t **)frame->data, // 输入数据缓冲区
                    frame->nb_samples);            // 每通道的采样数(帧数)

        // 通过帧数,音频格式,通道数计算每次转换后输出的字节数
        int out_buffer_size = av_samples_get_buffer_size(NULL,              // 传出值,与返回值相同
                                                         out_channel_nb,    // 通道数
                                                         frame->nb_samples, // 采样数(帧数)
                                                         out_sample_fmt,    // 音频格式
                                                         1);                // 对齐模式(1 - 紧凑,不对齐)

        // 转码后的数据写入文件(也可直接写入PCM进行播放)
        fwrite(out_buffer, 1, out_buffer_size, fp_pcm);
      }
    }
    av_free_packet(packet);
  }

  // 释放动态申请的内存
  av_frame_free(&frame);
  av_free(out_buffer);
  swr_free(&swrCtx);

  fclose(fp_pcm);                    // 关闭文件
  avcodec_close(pCodeCtx);           // 关闭解码器
  avformat_close_input(&pFormatCtx); // 关闭输入文件
  return 0;
}

编译选项:

-lavformat -lavcodec -lavutil -lswresample

转换后的文件测试:
由于没有文件头来指定音频格式,所以需要-f选项指定音频格式:

$ aplay -f cd out.pcm

数据结构及函数说明:

/*
 * 功能描述: 打开文件,解析文件格式
 * 返 回 值: 0 - 成功,负值 - 失败,发生错误
 */
int avformat_open_input(AVFormatContext **ps,    // 封装句柄
                        const char *url,         // 文件路径
                        AVInputFormat *fmt,      // 强制指定格式,一般为NULL
                        AVDictionary **options); // 一般设置为NULL

- 阅读全文 -

linux应用程序--磁盘管理


相关头文件:

#include <sys/statfs.h>

结构体说明:

struct statfs {
  long f_type;    // 文件系统类型
  long f_bsize;   // 传输块大小
  long f_blocks;  // 文件系统数据块总数
  long f_bfree;   // 可用块数
  long f_bavail;  // 非超级用户可获取的块数
  long f_files;   // 文件结点总数
  long f_ffree;   // 可用文件结点数
  fsid_t f_fsid;  // 文件系统标识 
  long f_namelen; // 文件名的最大长度
  long f_frsize;  // 碎片大小
  long f_flags;
  long f_spare[4];
};

函数原型:

/* 
 * 功能描述: 获取文件系统的相关参数
 * 参数说明: path - 文件系统路径(挂载点)
 *          info - 参数结构体指针(传出)  
 * 返 回 值: 0 - 成功, 其值 - 失败
 */
int statfs(const char *path, struct statfs *info);
int fstatfs(int fd, struct statfs *info);

- 阅读全文 -

clang-format详细说明


简要说明: 本文主要描述了clang-format应用说明,基于Vs Code测试。


设置Visual Code中应用

在工程根目录下新建.clang-format文件,内容如下:

# 表示注释,但貌似不支持中文

# 基于模板样式 LLVM,Google,Visual Studio,Mozillat,WebKit等
BasedOnStyle: LLVM

# 缩进字节数
IndentWidth: 2

# case标签是否缩进
IndentCaseLabels: true 

# Never表示空格代替制表符
UseTab: Never
# 制表符宽度
TabWidth: 2

# 每行限制字节数,超出此值后换行,0表示不限制
ColumnLimit: 0

# 最大的连续空行数
MaxEmptyLinesToKeep: 2

# 指针的*的挨着哪边(区分大小写)
PointerAlignment: Right

# 中括号两边添加空格 [] 
SpacesInSquareBrackets: false
# 小括号两边添加空格 ()
SpacesInParentheses : false
# 等号两边的空格
SpaceBeforeAssignmentOperators: true

# 注释对齐
AlignTrailingComments: true
# 多行声明语句对齐(不选)
AlignConsecutiveDeclarations: false
# 连续的赋值语句以 = 为中心对齐
AlignConsecutiveAssignments: true

大括号换行模式

BreakBeforeBraces: Allman

Attach  总是将大括号与上下文连在一起。
Linux   像Attach一样, 但是在一个方法、命名空间或一个类定义的大括号之前换行
Mozilla 像Attach一样, 但是在一个枚举、方法或记录定义前换行。
Stroustrup  像Attach一样,但是在方法定义、catch、和else前换行
WebKit  像Attach一样, 但是在方法前换行。
Allman  总是在大括号之前换行。
GNU     总是在括号前中断,并添加一个额外的级别的缩进到控件语句的括号中,而不是类、函数或其他定义的括号中。
Custom  在“BraceWrapping”里配置每一个单独的大括号。
BreakBeforeBraces: Custom
BraceWrapping: 
  # 注意这里的缩进,否则vscode格式化时报错  
  AfterClass:      false
  AfterFunction:   true           # 函数换行(一般为true)
  AfterControlStatement: true     # 控制块(if-else/while/switch等)
  AfterStruct:     true           # 结构体(不包括typedef)
  AfterUnion:      false          # 联合体
  AfterEnum:       true           # 枚举
  AfterNamespace:  false          # 命名空间
  AfterObjCDeclaration: false      
  BeforeCatch:     false          # catch与前边的花括号是否换行
  BeforeElse:      true           # else与前边的花括号是否换行
  IndentBraces:    false          # 缩进换行的大括号(一般为false)
# 结构体数组赋值时用的到,具体描述待查
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false

比较好看的配置:

BasedOnStyle: LLVM
IndentWidth: 2
IndentCaseLabels: true 
UseTab: Never
TabWidth: 2
ColumnLimit: 0
MaxEmptyLinesToKeep: 1
PointerAlignment: Right
SpacesInSquareBrackets: false
SpacesInParentheses : false
SpaceBeforeAssignmentOperators: true
AlignTrailingComments: true
AlignConsecutiveDeclarations: false
AlignConsecutiveAssignments:  true

BreakBeforeBraces: Custom
BraceWrapping:   
  AfterClass:      false
  AfterFunction:   true
  AfterControlStatement: true
  AfterStruct:     true
  AfterEnum:       true
  AfterNamespace:  false
  AfterObjCDeclaration: false      
  AfterUnion:      false
  BeforeCatch:     false
  BeforeElse:      true
  IndentBraces:    false

参考资料:
https://www.cnblogs.com/PaulpauL/p/5929753.html
https://www.jianshu.com/p/346f439d230c
https://www.jianshu.com/p/c2dd26fe6f78
https://blog.csdn.net/u013187057/article/details/85273775

- 阅读全文 -

vscode使用笔记


设置-->用户 指当前用户的配置,适用于所有工程,配置文件位于 ${用户目录}\AppData\Roaming\Code\User\settings.json;
设置-->工作区 指当工程的配置,优先级会覆盖用户设置,配置文件位于工程目录下的.vscode/setting.json;

在工程中排除目录或文件:

"files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true,
    "**/*.meta": true,
    "library/": true,
    "local/": true,
    "temp/": true    
}

其他设置项:

// 打开时猜测文件编码
"files.autoGuessEncoding": true,
// 编辑器字体设置
"editor.fontFamily": "Monaco, Consolas, 'Courier New', monospace",

添加至右键菜单:
新建menu.reg文件输入以下内容:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\VSCode]
@="Open with Code"
"Icon"="D:\\Program Files\\Microsoft VS Code\\Code.exe"

[HKEY_CLASSES_ROOT\*\shell\VSCode\command]
@="\"D:\\Program Files\\Microsoft VS Code\\Code.exe\" \"%1\""
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\VSCode]
@="Open with Code"
"Icon"="D:\\Program Files\\Microsoft VS Code\\Code.exe"

[HKEY_CLASSES_ROOT\Directory\shell\VSCode\command]
@="\"D:\\Program Files\\Microsoft VS Code\\Code.exe\" \"%V\""
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\VSCode]
@="Open with Code"
"Icon"="D:\\Program Files\\Microsoft VS Code\\Code.exe"

[HKEY_CLASSES_ROOT\Directory\Background\shell\VSCode\command]
@="\"D:\\Program Files\\Microsoft VS Code\\Code.exe\" \"%V\""

保存并双击执行导入注册表即可。

注意事项:

  1. 路径名称要和实际一致。
  2. 第一项表示任意文件右键菜单,第二项表示在目录上右键菜单,第三项表示在空白处右键(一般不用),具体说明请参考注册表相关章节。

Keil Assistant插件: 可用于编译,下载Keil工程
1.在商店中搜索Keil Assistant插件并安装。
2.在扩展设置(Extension Settings)中设置Keil软件的路径,(C51与MKD可分别设置)。
3.安装完成后,左侧资源管理器栏会出现KEIL UVISION PORJECT子菜单,即可打开keil工程,进行编译下载。

- 阅读全文 -


Copyright©2025 春天花会开, All Rights Reserved. Email: webmaster@oroct.com