• FFmpeg


    FFmpeg下载

    FFmpeg源码地址:https://github.com/FFmpeg/FFmpeg

    FFmpeg可执行文件地址:https://ffmpeg.org/download.html

    ffmpeg & ffplay & ffprobe参数介绍

    ffmpeg.exe

    ◆ 用于音视频转码, 也可以从url/现场音频/视频源抓取输入源等。笔者从网上摘抄了一部分ffmpeg常用参数如下(尤其在开发过程中,由于ffmpeg版本不同,ffmpeg参数也有少量出入,建议在命令行窗口输入“ffmpeg -h”查看本机部署的ffmpeg支持的参数):

     ffmpeg 范例

    //从视频第3秒开始剪切,持续4秒,并保存文件

    ffmpeg -ss 00:00:03 -t 00:00:04 -i test.mpg -vcodec copy -acodec copy test_cut.mpg

    ffplay.exe

    ◆ 一个非常简单和可移植的媒体播放器,使用FFmpeg库和SDL库。ffplay参数如下:

    ffplay.exe范例:

    //播放视频

    ffplay -i test.mpg

    ffprobe.exe

    ◆ 查看多媒体文件的信息。ffprobe参数如下

    ◆ ffprobe.exe范例:

    //查看视频文件的音频流和视频流信息

    ffprobe test.mpg

    ffmpeg解码

    音视频解码流程:

    windows使用SDL播放音视频,流程如下:

    代码:

    1. /*
    2. author:八小时码字员
    3. file:vPlayer_sdl2.cpp
    4. */
    5. #include "vPlayer_sdl2.h"
    6. #include "output_log.h"
    7. #include <stdio.h>
    8. #include <iostream>
    9. using namespace std;
    10. #define __STDC_CONSTANT_MACROS
    11. extern "C"
    12. {
    13. #include <libavcodec/avcodec.h>
    14. #include <libavformat/avformat.h>
    15. #include <libswscale/swscale.h>
    16. #include <libavutil/imgutils.h>
    17. #include <SDL.h>
    18. }
    19. static int g_frame_rate = 1;
    20. static int g_sfp_refresh_thread_exit = 0;
    21. static int g_sfp_refresh_thread_pause = 0;
    22. #define SFM_REFRESH_EVENT (SDL_USEREVENT+1)
    23. #define SFM_BREAK_EVENT (SDL_USEREVENT+2)
    24. typedef struct FFmpeg_V_Param_T
    25. {
    26. AVFormatContext *pFormatCtx;
    27. AVCodecContext *pCodecCtx;
    28. SwsContext *pSwsCtx;
    29. int video_index;
    30. }FFmpeg_V_Param;
    31. typedef struct SDL_Param_T
    32. {
    33. SDL_Window *p_sdl_window;
    34. SDL_Renderer *p_sdl_renderer;
    35. SDL_Texture *p_sdl_texture;
    36. SDL_Rect sdl_rect;
    37. SDL_Thread *p_sdl_thread;
    38. }SDL_Param;
    39. /*
    40. return value:zero(success) non-zero(failure)
    41. */
    42. int init_ffmpeg(FFmpeg_V_Param* p_ffmpeg_param, char* filePath)
    43. {
    44. //init FFmpeg_V_Param
    45. p_ffmpeg_param->pFormatCtx = avformat_alloc_context();
    46. const AVCodec *pCodec = NULL;
    47. //do global initialization of network libraries
    48. avformat_network_init();
    49. //open input stream
    50. if (avformat_open_input(&(p_ffmpeg_param->pFormatCtx), filePath, NULL, NULL) != 0)
    51. {
    52. output_log(LOG_ERROR, "avformat_open_input error");
    53. return -1;
    54. }
    55. //find stream info
    56. if (avformat_find_stream_info(p_ffmpeg_param->pFormatCtx, NULL) < 0)
    57. {
    58. output_log(LOG_ERROR, "avformat_find_stream_info error");
    59. return -1;
    60. }
    61. //get video pCodecParms, codec and frame rate
    62. for (int i = 0; i < p_ffmpeg_param->pFormatCtx->nb_streams; i++)
    63. {
    64. AVStream *pStream = p_ffmpeg_param->pFormatCtx->streams[i];
    65. if (pStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
    66. {
    67. pCodec = avcodec_find_decoder(pStream->codecpar->codec_id);
    68. p_ffmpeg_param->pCodecCtx = avcodec_alloc_context3(pCodec);
    69. avcodec_parameters_to_context(p_ffmpeg_param->pCodecCtx, pStream->codecpar);
    70. g_frame_rate = pStream->avg_frame_rate.num / pStream->avg_frame_rate.den;
    71. p_ffmpeg_param->video_index = i;
    72. }
    73. }
    74. if (!p_ffmpeg_param->pCodecCtx)
    75. {
    76. output_log(LOG_ERROR, "could not find video codecCtx");
    77. return -1;
    78. }
    79. //open codec
    80. if (avcodec_open2(p_ffmpeg_param->pCodecCtx, pCodec, NULL))
    81. {
    82. output_log(LOG_ERROR, "avcodec_open2 error");
    83. return -1;
    84. }
    85. //get scale pixelformat context
    86. p_ffmpeg_param->pSwsCtx = sws_getContext(p_ffmpeg_param->pCodecCtx->width,
    87. p_ffmpeg_param->pCodecCtx->height, p_ffmpeg_param->pCodecCtx->pix_fmt,
    88. p_ffmpeg_param->pCodecCtx->width, p_ffmpeg_param->pCodecCtx->height,
    89. AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
    90. av_dump_format(p_ffmpeg_param->pFormatCtx, p_ffmpeg_param->video_index, filePath, 0);
    91. return 0;
    92. }
    93. /*
    94. return value:zero(success) non-zero(failure)
    95. */
    96. int release_ffmpeg(FFmpeg_V_Param* p_ffmpeg_param)
    97. {
    98. if (!p_ffmpeg_param)
    99. return -1;
    100. //realse scale pixelformat context
    101. if (p_ffmpeg_param->pSwsCtx)
    102. sws_freeContext(p_ffmpeg_param->pSwsCtx);
    103. //close codec
    104. if (p_ffmpeg_param->pCodecCtx)
    105. avcodec_close(p_ffmpeg_param->pCodecCtx);
    106. //close input stream
    107. if (p_ffmpeg_param->pFormatCtx)
    108. avformat_close_input(&(p_ffmpeg_param->pFormatCtx));
    109. //free AVCodecContext
    110. if (p_ffmpeg_param->pCodecCtx)
    111. avcodec_free_context(&(p_ffmpeg_param->pCodecCtx));
    112. //free AVFormatContext
    113. if (p_ffmpeg_param->pFormatCtx)
    114. avformat_free_context(p_ffmpeg_param->pFormatCtx);
    115. //free FFmpeg_V_Param
    116. delete p_ffmpeg_param;
    117. p_ffmpeg_param = NULL;
    118. return 0;
    119. }
    120. int sfp_refresh_thread(void* opaque)
    121. {
    122. g_sfp_refresh_thread_exit = 0;
    123. g_sfp_refresh_thread_pause = 0;
    124. while (!g_sfp_refresh_thread_exit)
    125. {
    126. if (!g_sfp_refresh_thread_pause)
    127. {
    128. SDL_Event sdl_event;
    129. sdl_event.type = SFM_REFRESH_EVENT;
    130. SDL_PushEvent(&sdl_event);
    131. }
    132. SDL_Delay(1000 / g_frame_rate);
    133. }
    134. g_sfp_refresh_thread_exit = 0;
    135. g_sfp_refresh_thread_pause = 0;
    136. SDL_Event sdl_event;
    137. sdl_event.type = SFM_BREAK_EVENT;
    138. SDL_PushEvent(&sdl_event);
    139. return 0;
    140. }
    141. int init_sdl2(SDL_Param_T *p_sdl_param, int screen_w, int screen_h)
    142. {
    143. if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER))
    144. {
    145. output_log(LOG_ERROR, "SDL_Init error");
    146. return -1;
    147. }
    148. p_sdl_param->p_sdl_window = SDL_CreateWindow("vPlayer_sdl", SDL_WINDOWPOS_UNDEFINED,
    149. SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL);
    150. if (!p_sdl_param->p_sdl_window)
    151. {
    152. output_log(LOG_ERROR, "SDL_CreateWindow error");
    153. return -1;
    154. }
    155. p_sdl_param->p_sdl_renderer = SDL_CreateRenderer(p_sdl_param->p_sdl_window, -1, 0);
    156. p_sdl_param->p_sdl_texture = SDL_CreateTexture(p_sdl_param->p_sdl_renderer, SDL_PIXELFORMAT_IYUV,
    157. SDL_TEXTUREACCESS_STREAMING, screen_w, screen_h);
    158. p_sdl_param->sdl_rect.x = 0;
    159. p_sdl_param->sdl_rect.y = 0;
    160. p_sdl_param->sdl_rect.w = screen_w;
    161. p_sdl_param->sdl_rect.h = screen_h;
    162. p_sdl_param->p_sdl_thread = SDL_CreateThread(sfp_refresh_thread, NULL, NULL);
    163. return 0;
    164. }
    165. int release_sdl2(SDL_Param_T *p_sdl_param)
    166. {
    167. SDL_DestroyTexture(p_sdl_param->p_sdl_texture);
    168. SDL_DestroyRenderer(p_sdl_param->p_sdl_renderer);
    169. SDL_DestroyWindow(p_sdl_param->p_sdl_window);
    170. SDL_Quit();
    171. return 0;
    172. }
    173. int vPlayer_sdl2(char* filePath)
    174. {
    175. //ffmpeg param
    176. FFmpeg_V_Param *p_ffmpeg_param = NULL;
    177. AVPacket *packet = NULL;
    178. AVFrame *pFrame = NULL, *pFrameYUV = NULL;
    179. int out_buffer_size = 0;
    180. unsigned char* out_buffer = 0;
    181. //sdl param
    182. SDL_Param_T *p_sdl_param = NULL;
    183. SDL_Event sdl_event;
    184. int ret = 0;
    185. //init ffmpeg
    186. p_ffmpeg_param = new FFmpeg_V_Param();
    187. memset(p_ffmpeg_param, 0, sizeof(FFmpeg_V_Param));
    188. if (init_ffmpeg(p_ffmpeg_param, filePath))
    189. {
    190. ret = -1;
    191. goto end;
    192. }
    193. packet = av_packet_alloc();
    194. pFrame = av_frame_alloc();
    195. pFrameYUV = av_frame_alloc();
    196. out_buffer_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
    197. p_ffmpeg_param->pCodecCtx->width, p_ffmpeg_param->pCodecCtx->height, 1);
    198. out_buffer = (unsigned char*)av_malloc(out_buffer_size);
    199. av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer,
    200. p_ffmpeg_param->pCodecCtx->pix_fmt,
    201. p_ffmpeg_param->pCodecCtx->width, p_ffmpeg_param->pCodecCtx->height, 1);
    202. //init sdl2
    203. p_sdl_param = new SDL_Param_T();
    204. memset(p_sdl_param, 0, sizeof(SDL_Param_T));
    205. if (init_sdl2(p_sdl_param, p_ffmpeg_param->pCodecCtx->width, p_ffmpeg_param->pCodecCtx->height))
    206. {
    207. ret = -1;
    208. goto end;
    209. }
    210. //demuxing and show
    211. while (true)
    212. {
    213. int temp_ret = 0;
    214. SDL_WaitEvent(&sdl_event);
    215. if (sdl_event.type == SFM_REFRESH_EVENT)
    216. {
    217. while (true)
    218. {
    219. if (av_read_frame(p_ffmpeg_param->pFormatCtx, packet) < 0)
    220. {
    221. g_sfp_refresh_thread_exit = 1;
    222. break;
    223. }
    224. if (packet->stream_index == p_ffmpeg_param->video_index)
    225. {
    226. break;
    227. }
    228. }
    229. if (avcodec_send_packet(p_ffmpeg_param->pCodecCtx, packet))
    230. g_sfp_refresh_thread_exit = 1;
    231. do
    232. {
    233. temp_ret = avcodec_receive_frame(p_ffmpeg_param->pCodecCtx, pFrame);
    234. if (temp_ret == AVERROR_EOF)
    235. {
    236. g_sfp_refresh_thread_exit = 1;
    237. break;
    238. }
    239. if (temp_ret == 0)
    240. {
    241. sws_scale(p_ffmpeg_param->pSwsCtx, (const unsigned char* const*)pFrame->data,
    242. pFrame->linesize, 0, p_ffmpeg_param->pCodecCtx->height, pFrameYUV->data,
    243. pFrameYUV->linesize);
    244. SDL_UpdateTexture(p_sdl_param->p_sdl_texture, &(p_sdl_param->sdl_rect),
    245. pFrameYUV->data[0], pFrameYUV->linesize[0]);
    246. SDL_RenderClear(p_sdl_param->p_sdl_renderer);
    247. SDL_RenderCopy(p_sdl_param->p_sdl_renderer, p_sdl_param->p_sdl_texture,
    248. NULL, &(p_sdl_param->sdl_rect));
    249. SDL_RenderPresent(p_sdl_param->p_sdl_renderer);
    250. }
    251. } while (temp_ret != AVERROR(EAGAIN));
    252. //av_packet_unref(packet);
    253. }
    254. else if (sdl_event.type == SFM_BREAK_EVENT)
    255. {
    256. break;
    257. }
    258. else if (sdl_event.type == SDL_KEYDOWN)
    259. {
    260. if (sdl_event.key.keysym.sym == SDLK_SPACE)
    261. g_sfp_refresh_thread_pause = !g_sfp_refresh_thread_pause;
    262. if (sdl_event.key.keysym.sym == SDLK_q)
    263. g_sfp_refresh_thread_exit = 1;
    264. }
    265. else if (sdl_event.type == SDL_QUIT)
    266. {
    267. g_sfp_refresh_thread_exit = 1;
    268. }
    269. }
    270. end:
    271. release_ffmpeg(p_ffmpeg_param);
    272. av_packet_free(&packet);
    273. av_frame_free(&pFrame);
    274. av_frame_free(&pFrameYUV);
    275. release_sdl2(p_sdl_param);
    276. return ret;
    277. }
    1. /*
    2. author:八小时码字员
    3. file:output_log.cpp
    4. */
    5. #include
    6. #include
    7. #define MAX_BUF_LEN 1024
    8. int g_log_debug_flag = 1;
    9. int g_log_info_flag = 1;
    10. int g_log_warnning_flag = 1;
    11. int g_log_error_flag = 1;
    12. enum LOG_LEVEL
    13. {
    14. LOG_DEBUG,
    15. LOG_INFO,
    16. LOG_WARNING,
    17. LOG_ERROR
    18. };
    19. void set_log_flag(int log_debug_flag, int log_info_flag, int log_warnning_flag,
    20. int log_error_flag)
    21. {
    22. g_log_debug_flag = log_debug_flag;
    23. g_log_info_flag = log_info_flag;
    24. g_log_warnning_flag = log_warnning_flag;
    25. g_log_error_flag = log_error_flag;
    26. }
    27. void output_log(LOG_LEVEL log_level, const char* fmt, ...)
    28. {
    29. va_list args;
    30. va_start(args, fmt);
    31. char buf[MAX_BUF_LEN] = { 0 };
    32. vsnprintf(buf, MAX_BUF_LEN - 1, fmt, args);
    33. switch (log_level)
    34. {
    35. case LOG_DEBUG:
    36. if (g_log_debug_flag)
    37. printf("[Log-Debug]:%s\n", buf);
    38. break;
    39. case LOG_INFO:
    40. if (g_log_info_flag)
    41. printf("[Log-Info]:%s\n", buf);
    42. break;
    43. case LOG_WARNING:
    44. if (g_log_warnning_flag)
    45. printf("[Log-Warnning]:%s\n", buf);
    46. break;
    47. case LOG_ERROR:
    48. if (g_log_error_flag)
    49. printf("[Log-Error]:%s\n", buf);
    50. break;
    51. default:
    52. break;
    53. }
    54. va_end(args);
    55. }

    ffmpeg编码

    (视频)使用FFmpeg库编码YUV:

    FFmpeg编码音频(PCM):

    FFmpeg转码

    转码比较好理解,就是将解码和编码结合起来,过程为:解封装->解码->编码->封装。逻辑如下:

    ◆ 解封装:将音视频文件的封装格式去掉,获取视频流(H.264)和音频流(AAC)

    ◆ 解码:将视频流解码成原始图像数据(YUV),将音频流解码成原始音频数据(PCM)

    ◆ 编码:将原始图像(YUV)进行编码(MPG2),将音频流进行编码(MP3)

    ◆ 封装:将视频流和音频流封装成视频文件

    FFmpeg结构体

    FFmpeg结构体主要分为三个层次:协议层(AVIOContext)、封装层(AVInputFormat)、解码层(AVStream)。具体如下: 

    关键结构体主要有以下八个:

    AVFormatContext

    描述媒体文件或媒体流的构成和基本信息,贯穿ffmpeg使用整个流程

    1. AVInputFormat *iformat、AVOutputFormat *oformat:输入或者输出流的格式(只能存在一个)
    2. AVIOContext *pb:管理输入输出数据
    3. unsigned int nb_streams:音视频流的个数
    4. AVStream **streams:音视频流
    5. char *url:文件名
    6. int64_t duration:时长
    7. int bit_rate:比特率(单位bite/s)
    8. AVDictionary *metadata:元数据(查看元数据:ffprobe filename)

    AVInputFormat

    文件的封装格式

    1. char* name:封装格式的名字
    2. char* long_name:封装格式的长名字
    3. char* extensions:文件扩展名

    AVIOContext->URLContext->URLProtocol

    AVIOContext

    文件(协议)操作的顶层对象

    1. unsigned char *buffer:缓冲开始位置
    2. int buffer_size:缓冲区大小(默认32768
    3. unsigned char *buf_ptr:当前指针读取到的位置
    4. unsigned char *buf_end:缓存结束的位置
    5. void *opaque:URLContext结构体
    6. (*read_packet)(...):读取音视频数据的函数指针
    7. (*write_packet)(...):写入音视频数据的函数指针
    8. (*read_pause)(...):网络流媒体协议的暂停或恢复播放函数指针

    URLContext

    每种协议,有一个协议操作对象和一个关联的协议对象

    1. char* name:协议名称
    2. const struct URLProtocol *prot:协议操作对象(ff_file_protocol、ff_librtmp_protocol...)
    3. void *priv_data:协议对象(FileContext、LibRTMPContext)

    URLProtocol

    协议操作对象

    AVStream

    存储音频流或视频流的结构体

    1. int index:音频流或视频流的索引
    2. AVRational time_base:计算pts或dts是使用的时间戳基本单位(显示时间:pt = av_q2d(video_stream->time_base) * frame->pts)
    3. int64_t duration:该视频/音频流长度
    4. AVRational avg_frame_rate:平均帧率(对于视频来说,frame_rate=avg_frame_rate.num / avg_frame_rate.den)
    5. AVCodecParameters *codecpar:解码器参数

    AVCodecParameter 和 AVCodecContext

    ◆新的 ffmpeg 中 AVStream.codecpar(struct AVCodecParameter) 代替 AVStream.codec(struct AVCodecContext):AVCodecParameter 是由 AVCodecContext 分离出来的,AVCodecParameter中没有函数

      ◆AVCodecContext 结构体仍然是编解码时不可或缺的结构体:avcodec_send_packet 和 avcodec_receive_frame 使用 AVCodecContext

        ◆ AVCodecContext 和 AVCodec 的获取方法 

    1. //=============== new version code ===============
    2. char filePath[] = "test.mp4";
    3. AVFormatContext *pFormatCtx;
    4. AVCodecContext *pCodecCtx;
    5. AVCodec *pCodec;
    6. pFormatCtx = avformat_alloc_context();
    7. av_register_all();
    8. avformat_network_init();
    9. avformat_open_input(&pFormatCtx, filePath, NULL, NULL);
    10. avformat_find_stream_info(pFormatCtx, NULL);
    11. for (int i = 0; i < pFormatCtx->nb_streams; i++)
    12. {
    13. AVStream *pStream = pFormatCtx->streams[i];
    14. pCodec = avcodec_find_decoder(pStream->codecpar->codec_id);
    15. pCodecCtx = avcodec_alloc_context3(pCodec);
    16. avcodec_parameters_to_context(pCodecCtx, pStream->codecpar);
    17. }
    1. //============ old version code ============
    2. char filePath[] = "test.mp4";
    3. AVFormatContext *pFormatCtx;
    4. AVCodecContext *pCodecCtx;
    5. AVCodec *pCodec;
    6. pFormatCtx = avformat_alloc_context();
    7. av_register_all();
    8. avformat_network_init();
    9. avformat_open_input(&pFormatCtx, filePath, NULL, NULL);
    10. avformat_find_stream_info(pFormatCtx, NULL);
    11. for (int i = 0; i < pFormatCtx->nb_streams; i++)
    12. {
    13. AVStream *pStream = pFormatCtx->streams[i];
    14. pCodecCtx = pStream->codec;
    15. pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    16. }

    ◆ 关键参数:可参考 avcodec_parameters_to_context 源码

    1. num AVMediaType codec_type:编解码器的类型(视频,音频...)
    2. enum AVCodecID codec_id:标示特定的编码器
    3. AVCodecContext:struct AVCodec *codec:采用的解码器AVCodec(H.264,MPEG2...)
    4. int bit_rate:平均比特率
    5. uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
    6. AVCodecContext:enum AVPixelFormat pix_fmt:像素格式(视频)
    7. int width, height:宽和高(视频)
    8. AVCodecContext:enum AVSampleFormat sample_fmt:采样格式(音频)
    9. int sample_rate:采样率(音频)
    10. int channels:声道数(音频)
    11. uint64_t channel_layout:声道格式
    12. AVCodecParameters:int format:像素格式(视频)/采样格式(音频

     AVCodec

    编解码器结构体

    ◆ 每一个解码器对应一个AVCodec结构体,比如:AVCodec ff_h264_decoder,AVCodec ff_jpeg2000_decoder

        ◆ 关键成员变量如下:

    1. const char *name:编解码器短名字(形如:"h264"
    2. const char *long_name:编解码器全称(形如:"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"
    3. enum AVMediaType type:媒体类型:视频、音频或字母
    4. enum AVCodecID id:标示特定的编码器
    5. const AVRational *supported_framerates:支持的帧率(仅视频)
    6. const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
    7. const int *supported_samplerates:支持的采样率(仅音频)
    8. const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
    9. const uint64_t *channel_layouts:支持的声道数(仅音频

    AVPacket

    存储解码前数据的结构体

        ◆ 关键成员变量

    1. AVBufferRef *buf:管理data指向的数据
    2. uint8_t *data:压缩编码的数据
    3. int size:data的大小
    4. int64_t pts:显示时间戳
    5. int64_t dts:解码时间戳
    6. int stream_index:标识该AVPacket所属的视频/音频流

    ◆ AVPacket的内存管理:AVPacket本身并不包含压缩的数据,通过data指针引用数据的缓存空间

        ◆ 多个AVPacket共享同一个数据缓存(AVBufferRef、AVBuffer)

        ◆ AVPacket拥有独立的数据缓存

    1. av_read_frame(pFormatCtx, packet) // 读取Packet
    2. av_packet_ref(dst_pkt,packet) // dst_pkt 和 packet 共享同一个数据缓存空间,引用计数+1
    3. av_packet_unref(dst_pkt); //释放 pkt_pkt 引用的数据缓存空间,引用计数-1

    ◆ AVBuffer 关键成员变量

    1. uint8_t *data:压缩编码的数据
    2. size_t size:数据长度
    3. atomic_uint refcount:引用计数,如果引用计数为0,则释放数据缓存空间

    AVFrame

    存储解码后数据的结构体

    1. uint8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)
    2. int linesize[AV_NUM_DATA_POINTERS]:data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。
    3. int width, height:视频帧宽和高(1920x1080,1280x720...)
    4. int nb_samples:音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个
    5. int format:解码后原始数据类型(YUV420,YUV422,RGB24...)
    6. int key_frame:是否是关键帧
    7. enum AVPictureType pict_type:帧类型(I,B,P...)
    8. AVRational sample_aspect_ratio:图像宽高比(16:9,4:3...)
    9. int64_t pts:显示时间戳
    10. int coded_picture_number:编码帧序号
    11. int display_picture_number:显示帧序号

  • 相关阅读:
    【Unity每日一记】音频,麦克风,粒子和拖尾渲染器
    Django常用命令
    美颜SDK集成指南:为应用添加视频美颜功能
    创意中秋与国庆贺卡 - 用代码为节日增添喜悦
    newstarctf
    测试工程师的简历到底怎么写?
    知乎服务化的实践与思考
    【无标题】
    STL 红黑树源码分析
    读书笔记<高速上手C11 14 17>
  • 原文地址:https://blog.csdn.net/weixin_44273624/article/details/134401264