基于ffmpeg读取实时码流

从内存中读取数据

ffmpeg一般情况下支持打开一个本地文件,例如“C:\test.avi”

或者是一个流媒体协议的URL,例如“rtmp://222.31.64.208/vod/test.flv”

其打开文件的函数是avformat_open_input(),直接将文件路径或者流媒体URL的字符串传递给该函数就可以了。

但其是否支持从内存中读取数据呢?这个问题困扰了我很长时间。当时在做项目的时候,通过Winpcap抓取网络上的RTP包,打算直接送给ffmpeg进行解码。一直没能找到合适的方法。因为抓取的数据包是存在内存中的,所以无法传递给avformat_open_input()函数其路径(根本没有路径= =)。当然也可以将抓取的数据报存成文件,然后用ffmpeg打开这个文件,但是这样的话,程序的就太难控制了。

后来经过分析ffmpeg的源代码,发现其竟然是可以从内存中读取数据的,代码很简单,如下所示:

 


 
  1. AVFormatContext *ic = NULL;

  2. ic = avformat_alloc_context();

 


 
  1. unsigned char * iobuffer=(unsigned char *)av_malloc(32768);

  2. AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);

  3. ic->pb=avio;

  4. err = avformat_open_input(&ic, "nothing", NULL, NULL);


关键要在avformat_open_input()之前初始化一个AVIOContext,而且将原本的AVFormatContext的指针pb(AVIOContext类型)指向这个自行初始化AVIOContext。当自行指定了AVIOContext之后,avformat_open_input()里面的URL参数就不起作用了。示例代码开辟了一块空间iobuffer作为AVIOContext的缓存。

 

fill_iobuffer则是将数据读取至iobuffer的回调函数。fill_iobuffer()形式(参数,返回值)是固定的,是一个回调函数,如下所示(只是个例子,具体怎么读取数据可以自行设计)。示例中回调函数将文件中的内容通过fread()读入内存。

 


 
  1. //读取数据的回调函数-------------------------

  2. //AVIOContext使用的回调函数!

  3. //注意:返回值是读取的字节数

  4. //手动初始化AVIOContext只需要两个东西:内容来源的buffer,和读取这个Buffer到FFmpeg中的函数

  5. //回调函数,功能就是:把buf_size字节数据送入buf即可

  6. //第一个参数(void *opaque)一般情况下可以不用

  7. int fill_iobuffer(void * opaque,uint8_t *buf, int bufsize){

  8. if(!feof(fp_open)){

  9. int true_size=fread(buf,1,buf_size,fp_open);

  10. return true_size;

  11. }else{

  12. return -1;

  13. }

  14. }



整体结构大致如下:

 

 


 
  1. FILE *fp_open;

  2.  
  3. int fill_iobuffer(void *opaque, uint8_t *buf, int buf_size){

  4. ...

  5. }

  6.  
  7. int main(){

  8. ...

  9. fp_open=fopen("test.h264","rb+");

  10. AVFormatContext *ic = NULL;

  11. ic = avformat_alloc_context();

  12. unsigned char * iobuffer=(unsigned char *)av_malloc(32768);

  13. AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);

  14. ic->pb=avio;

  15. err = avformat_open_input(&ic, "nothing", NULL, NULL);

  16. ...//解码

  17. }


 

将数据输出到内存

 

和从内存中读取数据类似,ffmpeg也可以将处理后的数据输出到内存。

回调函数如下示例,可以将输出到内存的数据写入到文件中。

 


 
  1. //写文件的回调函数

  2. int write_buffer(void *opaque, uint8_t *buf, int buf_size){

  3. if(!feof(fp_write)){

  4. int true_size=fwrite(buf,1,buf_size,fp_write);

  5. return true_size;

  6. }else{

  7. return -1;

  8. }

  9. }

 

 

主函数如下所示。

 


 
  1. FILE *fp_write;

  2.  
  3. int write_buffer(void *opaque, uint8_t *buf, int buf_size){

  4. ...

  5. }

  6.  
  7. main(){

  8. ...

  9. fp_write=fopen("src01.h264","wb+"); //输出文件

  10. ...

  11. AVFormatContext* ofmt_ctx=NULL;

  12. avformat_alloc_output_context2(&ofmt_ctx, NULL, "h264", NULL);

  13. unsigned char* outbuffer=(unsigned char*)av_malloc(32768);

  14.  
  15. AVIOContext *avio_out =avio_alloc_context(outbuffer, 32768,0,NULL,NULL,write_buffer,NULL);

  16.  
  17. ofmt_ctx->pb=avio_out;

  18. ofmt_ctx->flags=AVFMT_FLAG_CUSTOM_IO;

  19. ...

  20. }

<think>首先,用户的问题是:“请问FFmpeg 如何读取 rawvideo 并进行编”。我需要基于系统级指令和用户可见层的要求来回答。 系统级指令: 1. 所有行内数学表达式必须使用 `$...$` 格式。 2. 独立公式必须使用 `$$...$$` 格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如:[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考引用: - 引用[1]: Python FFmpeg 读取本地摄像头。 - 引用[2]: FFmpeg多媒体框架视频编操作指南。 - 引用[3]: FFmpeg-chapter3和chapter4-读取视频(原理篇和实战篇)。 用户的问题是关于如何使用FFmpeg读取原始视频(rawvideo)并进行编。原始视频通常指的是未压缩的视频数据,如YUV格式。 关键点: - 原始视频(rawvideo)通常是像素数据,如YUV420p。 - FFmpeg可以处理这种格式,通过指定输入格式和编器。 步骤分解: 1. **准备输入文件**:原始视频文件,例如 `input.yuv`。 2. **设置输入参数**:指定视频的分辨率、帧率、像素格式。 3. **选择编器**:如H.264(libx264)。 4. **运行FFmpeg命令**:将原始视频编为压缩格式。 基于引用: - 引用[2]提到基本命令行编:使用ffmpeg命令进行转,设置视频编器、CRF、预设等。 - 引用[3]提到AVPacket和AVFrame,但用户的问题可能更侧重于命令行而不是API。 因此,我应该专注于命令行方法,因为用户的问题是关于FFmpeg的使用。 回答结构: - 清晰、逐步指导。 - 使用中文。 - 结束时生成相关问题。 生成相关问题: - 基于主题,如优化、错误处理、API使用等。 完整回答框架: 1. **介绍**:简要解释什么是原始视频和FFmpeg的处理方式。 2. **步骤**: - 步骤1:准备原始视频文件。 - 步骤2:使用FFmpeg命令读取并编。 - 详细命令示例。 - 解释关键参数。 3. **注意事项**:如像素格式、分辨率的重要性。 4. **生成相关问题**:在最后添加。 引用标识: - 如果引用参考内容,在末尾添加[^1]、[^2]等。例如,基于引用[2],添加引用标识。 数学表达式: - 用户的问题不涉及数学,但如果提到率计算等,可以使用行内数学,如 `$R = \text{率}$`。但这里可能不需要。 最终回答: - 使用中文。 - 确保真实可靠:基于FFmpeg文档和常见用法。</think>### FFmpeg 读取原始视频(rawvideo)并进行编 原始视频(rawvideo)通常指未压缩的像素数据,如 YUV 格式(例如 YUV420p),它不包含编头信息。FFmpeg 支持直接读取此类文件并进行高效编。以下步骤基于 FFmpeg 命令行工具(推荐给大多数用户),结构清晰,逐步指导您完成过程。确保已安装 FFmpeg(可从官网下载或通过包管理器安装如 `sudo apt install ffmpeg`)。 #### 步骤 1: 准备原始视频文件 - **文件要求**:原始视频文件必须是纯像素数据,常见格式如 `.yuv` 或 `.rgb`。文件需包含分辨率、帧率和像素格式信息。 - 例如:`input.yuv`,分辨率为 1920x1080,帧率 30fps,像素格式为 YUV420p。 - 如果文件缺失元数据,FFmpeg 无法自动识别,需手动指定参数[^2]。 #### 步骤 2: 使用 FFmpeg 命令行读取并编 FFmpeg 的基本命令结构为: ```bash ffmpeg -f rawvideo -pixel_format <像素格式> -video_size <宽度>x<高度> -framerate <帧率> -i <输入文件> -c:v <编器> <输出文件> ``` - **关键参数说明**: - `-f rawvideo`: 指定输入格式为原始视频。 - `-pixel_format`: 设置像素格式(如 `yuv420p`、`rgb24`),必须与文件一致。 - `-video_size`: 分辨率(如 `1920x1080`)。 - `-framerate`: 帧率(如 `30`)。 - `-i <输入文件>`: 输入文件路径(如 `input.yuv`)。 - `-c:v`: 视频编器(如 `libx264` 用于 H.264)。 - 输出文件:指定格式(如 `.mp4`、`.mkv`)。 **完整示例命令**: 将 YUV420p 原始文件编为 H.264 MP4: ```bash ffmpeg -f rawvideo -pixel_format yuv420p -video_size 1920x1080 -framerate 30 -i input.yuv -c:v libx264 -crf 23 -preset medium output.mp4 ``` - **参数细节**: - `-crf 23`: 控制质量(0=无损,23=默认,51=最差)。 - `-preset medium`: 平衡编速度和压缩率(可选 `fast`、`slow` 等)。 - 更多编选项参考[^2]。 #### 步骤 3: 验证和处理错误 - **验证输出**:播放输出文件(如 `ffplay output.mp4`)检查质量。 - **常见错误**: - **像素格式不匹配**:如果报错 `[rawvideo] Invalid pixel format`,确保 `-pixel_format` 正确(可用 `ffmpeg -pix_fmts` 查看支持格式)。 - **分辨率或帧率错误**:导致视频撕裂或卡顿,需精确匹配文件。 - **权限问题**:确保输入文件可读,输出目录可写[^2]。 - **优化建议**:对于大文件,添加 `-threads auto` 启用多线程加速。 #### 注意事项 - **性能考量**:原始视频文件通常很大(例如 1080p YUV420p 视频约 1.5MB/帧),编时需足够内存。CRF 值越低,质量越高但文件越大;preset 越慢,压缩率越高但耗时更长[^2]。 - **API 扩展(针对开发者)**:如果需 Python 集成,可使用 `ffmpeg-python` 库(基于引用[1]),但命令行更简单高效。核心原理是通过 `avcodec_send_frame()` 发送原始帧数据到编器[^3]。 通过以上步骤,您可以高效地将原始视频转换为压缩格式。FFmpeg 的灵活性使其成为处理 rawvideo 的首选工具[^1][^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值