每次从H.264文件读入一定数据量的数据,模拟输入H.264流,最终输出封装格式文件。

//H264ToContainer_Win32.h
extern "C"
{//@param r_frame_rate 输入的H.264流帧率//@param buffer_size_max 传入数据的最大尺寸__declspec(dllexport) AVFormatContext *format_initialise(const char *out_filename, float r_frame_rate, int buffer_size_max);//@param data 每次输入的数据//@param buffer_size 每次传入的数据尺寸可以不同,但不能大于format_initialise()的参数buffer_size_max__declspec(dllexport) AVFormatContext *format_data_import(AVFormatContext *ofmt_ctx, uint8_t *data, int buffer_size);__declspec(dllexport) int format_close(AVFormatContext *ofmt_ctx);
}
// H264ToContainer_Win32.cpp : Defines the exported functions for the DLL application.
//#include "stdafx.h"#define __STDC_CONSTANT_MACROSextern "C"
{
#include "libavformat/avformat.h"
}
#include "H264ToContainer_Win32.h"static uint8_t *temp;AVFormatContext *format_initialise(const char *out_filename, float r_frame_rate, int buffer_size_max)
{AVOutputFormat *ofmt = NULL;AVFormatContext *ofmt_ctx = NULL;int ret;av_register_all();avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);if (!ofmt_ctx) {printf("Could not create output context\n");ret = AVERROR_UNKNOWN;goto end;}ofmt = ofmt_ctx->oformat;AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec) {printf("Could not find encoder for '%s'\n",avcodec_get_name(AV_CODEC_ID_H264));goto end;}AVStream *out_stream = avformat_new_stream(ofmt_ctx, codec);if (!out_stream) {printf("Failed allocating output stream\n");ret = AVERROR_UNKNOWN;goto end;}out_stream->codec->codec_tag = 0;/* Some formats want stream headers to be separate. */if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;printf("==========Output Information==========\n");av_dump_format(ofmt_ctx, 0, out_filename, 1);printf("======================================\n");//Open output fileif (!(ofmt->flags & AVFMT_NOFILE)) {if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE) < 0) {printf("Could not open output file '%s'", out_filename);goto end;}}//虽然不起作用,但必须设置AVCodecContext中的width和height,//否则,调avformat_write_header()时,报错:dimensions not set.ofmt_ctx->streams[0]->codec->width = 1;ofmt_ctx->streams[0]->codec->height = 1;out_stream->r_frame_rate.num = r_frame_rate * 1000;out_stream->r_frame_rate.den = 1000;//Write file headerif (avformat_write_header(ofmt_ctx, NULL) < 0) {printf("Error occurred when opening output file\n");goto end;}//buffer_size_max为每次传入数据的最大尺寸.//为temp分配空间要考虑到上一次可能剩余IDR帧尺寸最大值,预留100000字节.if (buffer_size_max < 60000){//temp为临时缓冲区,存储上一次传入数据剩余的不完整帧和本次传入的数据。temp = (uint8_t *)malloc(5 * 32768);}else{//temp为临时缓冲区,存储上一次传入数据剩余的不完整帧和本次传入的数据。temp = (uint8_t *)malloc(100000 + buffer_size_max);}return ofmt_ctx;end:/* close output */if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))avio_close(ofmt_ctx->pb);avformat_free_context(ofmt_ctx);return 0;
}AVFormatContext *format_data_import(AVFormatContext *ofmt_ctx, uint8_t *data, int buffer_size)
{//上一次传入数据剩余的不完整帧的大小。static int residue_len = 0;static int frame_index = 0;memcpy(temp + residue_len, data, buffer_size);int frame_header = 0;//之所以从j==1开始,是因为j==0必然是帧头,现在要找的是下一个帧头for (int j = 1; j <= residue_len + buffer_size - 5; j++){if (temp[j] == 0x00 && temp[j + 1] == 0x00 && temp[j + 2] == 0x00 && temp[j + 3] == 0x01 && temp[j + 4] != 0x68){AVPacket *pkt = av_packet_alloc();av_init_packet(pkt);pkt->size = j - frame_header;pkt->data = (uint8_t *)malloc(j - frame_header);memcpy(pkt->data, temp + frame_header, j - frame_header);//认为带SPS信息的为关键帧。若不正确标记关键帧,则不能正常随机定位或快进快退。if (temp[frame_header + 4] == 0x67){pkt->flags |= AV_PKT_FLAG_KEY;}AVRational time_base = ofmt_ctx->streams[0]->time_base;//Duration between 2 frames (μs)int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(ofmt_ctx->streams[0]->r_frame_rate);pkt->pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base)*AV_TIME_BASE);pkt->duration = (double)calc_duration / (double)(av_q2d(time_base)*AV_TIME_BASE);frame_index++;printf("Write 1 Packet. size:%5d\tpts:%lld\n", pkt->size, pkt->pts);if (av_interleaved_write_frame(ofmt_ctx, pkt) < 0){printf("Error muxing packet\n");}av_packet_free(&pkt);frame_header = j;}else{continue;}}residue_len = residue_len + buffer_size - frame_header;//即使有重叠区域,也允许这样进行内存拷贝,要拷贝的尾部数据会覆盖temp+frame_header以后的重叠区域。memcpy(temp, temp + frame_header, residue_len);return ofmt_ctx;}int format_close(AVFormatContext *ofmt_ctx)
{free(temp);//Write file trailerav_write_trailer(ofmt_ctx);/* close output */if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))avio_close(ofmt_ctx->pb);avformat_free_context(ofmt_ctx);return 0;
}
// test.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#define __STDC_CONSTANT_MACROSextern "C"
{
#include "libavformat/avformat.h"
}
#include "H264ToContainer_Win32.h"
#define BUFFER_SIZE 32768int _tmain(int argc, _TCHAR* argv[])
{const char *in_filename_v = "media files/JINUSEAN_17s.h264"; //Input file URLconst char *out_filename = "media files/JINUSEAN_17s.mkv"; //Output file URLfloat r_frame_rate = 29.97;AVFormatContext *ofmt_ctx = format_initialise(out_filename, r_frame_rate, BUFFER_SIZE);FILE *fp_open = fopen(in_filename_v, "rb+");for (int i = 0; i < 200; i++){uint8_t *buf = (uint8_t *)malloc(BUFFER_SIZE);fread(buf, 1, BUFFER_SIZE, fp_open);ofmt_ctx = format_data_import(ofmt_ctx, buf, BUFFER_SIZE);free(buf);}format_close(ofmt_ctx);return 0;
}

模拟输入H.264流,输出封装格式文件(API版)相关推荐

  1. 模拟输入H.264流,输出封装格式文件

    /***每次从H.264文件读取IO_BUFFER_SIZE字节的数据,*模拟输入H.264流,最终输出封装格式文件.*/ #include "stdafx.h"#define _ ...

  2. 利用FFmpeg将H.264文件读入内存,再输出封装格式文件

    /***先将H.264文件读入内存,*再输出封装格式文件.*/ #include "stdafx.h"#define __STDC_CONSTANT_MACROSextern &q ...

  3. 输入H.264流,输出封装格式流

    //H264ToContainer_Win32.h extern "C" {//@param format_name 输出流的格式名//@param r_frame_rate 输入 ...

  4. 使用FFmpeg的SDK库实现将H.264流封装进MP4文件时全局SPS、PPS与流中SPS、PPS冲突的问题

    一.问题 1. 使用FFmpeg的SDK库实现将H.264流封装进MP4文件的源码大致如下: char* filename = "./test.mp4" AVOutputForma ...

  5. 利用转换流将GBK格式文件以UTF-8输出

    3.利用转换流将GBK格式文件以UTF-8输出 解题思路:       1,InputStreamReader(File file,"gbk");读入文件       2,Outp ...

  6. H.264视频RTP负载格式/NALU的类型

    1. 网络抽象层单元类型(NALU) NALU 头由一个字节组成, 它的语法如下:       +===============+       |0|1|2|3|4|5|6|7|       +=+= ...

  7. H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式

    H.264 RTPpayload 格式------ H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +------------ ...

  8. H.264的RTP封装(下)

    H.264的RTP封装(下) 3. RTP封装实现 3.1 封装程序流程图 4. RTP解封装实现 4.1 解封装程序流程图 5. 总结 愚见,望指正! 6. 参考文献 [1] Schuzrinne ...

  9. H.264(H264)视频文件的制作

    一.准备工作 1.下载并安装优酷客户端 2.下载ffmpeg可执行文件,解压可用,不需要下载源码自己编译. ffmpeg可执行文件下载链接:http://download.csdn.net/detai ...

最新文章

  1. 2021年必读的10 个计算机视觉论文总结
  2. python structure_GitHub - CYZYZG/Data_Structure_with_Python: 这是我在学习《基于Python的数据结构》的时候的笔记与代码...
  3. 直播 | AAAI 2021:文本对抗攻防中的对抗训练方法
  4. 【转】软件需求分析方法
  5. 关于 ASP.NET 内存缓存你需要知道的 10 点
  6. imp命令导入指定表_Sqoop 使用shell命令的各种参数的配置及使用方法
  7. C++(STL):03---智能指针之shared_ptr
  8. DataReceivedEventHandler 委托 接收调用执行进程返回数据
  9. 【数据结构笔记08】哨兵查找、二分查找、树、儿子-兄弟表示法、二叉树的引子
  10. (OCR公式)Mathpix Snipping Tool
  11. 大厂的 404 页面都长啥样?看到最后一个,我笑了。。。
  12. PReLU, LReLU, ReLU
  13. 树莓派raspberry pi 4 SSH默认密码无法登录解决办法
  14. 墨卡托投影参数设置_横轴墨卡托投影坐标设置与导入导出CAD文件讲解
  15. C# 正则表达式数字匹配
  16. iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 80 -j DNAT ...
  17. 3.数据的一致性与一致性算法(CAP原则、Paxos算法、Raft算法、ZAB协议)
  18. 比尔.盖兹另辟Vista新战场?
  19. 开发人员看测试之TDD和BDD
  20. 500多公里上空拍摄的毕业照!你一定没见过...

热门文章

  1. unity物理碰撞检测和触发器碰撞检测的区别
  2. 备忘4:爬取微博热门信息以及所有热门微博转发的用户信息
  3. 【数字IC/FPGA】仲裁器进阶--Round Robin Arbiter
  4. LM13丨形态量化-动量周期分析
  5. Unity-Rigidbody【刚体】组件-Rigidbody.AddForce的ForceMode 力的模式
  6. 抽奖!送一箱 GitHub 周边
  7. 【文献学习】热电偶信号调理电路
  8. SQL查询选修了全部课程的学生姓名
  9. Ubuntu安装Visual studio code(VScode),并配置远程资源管理器,VScode安装服务器(SSH)
  10. 全球及中国便捷式GNSS接收器行业供应需求及项目投资战略分析报告2022-2027年