h264文件不能直接在网页上播放,比如在浏览器上输入http://10.0.0.2/2022-01-08T22-32-58.h264,变成了下载。

若在浏览器上输入http://10.0.0.2/2022-01-08T22-32-58.mp4,则可以播放。

本文讲解用ffmpeg将h264文件转换成mp4。

首先,准备h264文件,这个可以用ffmpeg将一个mp4的视频部分转成h264,命令如下:

ffmpeg -i 2022-01-08T22-32-58.mp4 -an -vcodec copy 2022-01-08T22-32-58.h264

注意,我这里mp4里面的视频编码格式是h264,故用的vcodec copy,否则用vcodec libx264。

下面是将这个2022-01-08T22-32-58.h264封装成mp4,注意,没有解码编码过程,速度会很快。
大概过程如下:
1.启动两个线程
2.第一个线程av_read_frame读到packet,然后av_packet_clone拷贝出一个packet,塞入队列
3.第二个线程从队列中读取packet,进行pts,dts,duration设置,然后调用av_interleaved_write_frame写入。

这里面需要注意的地方在于pts,dts的设置,从ffmpeg源码上看,对于pts,dts的设置,也是很麻烦的,源码中,很多地方,动不动就看pts,dts是否需要设置。

本人之前采取下列方式进行dts和pts的设置,即由于读的context和写入的context的时间基(time_base)不一致,需要转换成目标文件context的时间基。

pPacketVideoA->dts = av_rescale_q_rnd(pPacketVideoA->dts, m_pFormatCtx_File->streams[m_iVideoIndex]->time_base, m_pFormatCtx_Out->streams[m_iVideoIndex]->time_base, AVRounding(1));

但实际运行时,出现了问题,读取出来的packet的pts和dts都是AV_NOPTS_VALUE,经过转换还是AV_NOPTS_VALUE,然后调用av_interleaved_write_frame出错。

最后调试ffmpeg源码,得到pts和dts的处理如下:

pPacketVideoA->duration = av_rescale_q_rnd(pPacketVideoA->duration, m_pFormatCtx_File->streams[m_iVideoIndex]->time_base, m_pFormatCtx_Out->streams[m_iVideoIndex]->time_base, AVRounding(1));
if (pPacketVideoA->dts != AV_NOPTS_VALUE)
{pPacketVideoA->dts = av_rescale_q_rnd(pPacketVideoA->dts, m_pFormatCtx_File->streams[m_iVideoIndex]->time_base, m_pFormatCtx_Out->streams[m_iVideoIndex]->time_base, AVRounding(1));pPacketVideoA->pts = pPacketVideoA->dts;
}
else
{pPacketVideoA->pts = pPacketVideoA->dts = m_iTotalDuration;
}
m_iTotalDuration += pPacketVideoA->duration;

m_iTotalDuration的初始值,本人设置的是0,即第一帧的pts和dts都设置成0,下一帧的dts就是前面总帧的duration和,这个是ffmpeg里面的逻辑。

当然,ffmpeg里面判断复杂多了,比如参考了是否有B帧,本人所写的没考虑B帧,只考虑一个文件里面只有I帧,P帧的情况。

下面是代码结构

其中FfmpegH264ToMp4.cpp的内容如下:

// FfmpegH264ToMp4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include "H264ToMp4.h"int main()
{CVideoConvert cVideoConvert;std::string strVideoFile = "2022-01-08T22-32-58.h264";std::string strOutFile = "out.mp4";cVideoConvert.StartConvert(strVideoFile, strOutFile);cVideoConvert.WaitFinish();return 0;
}

H264ToMp4.h里面的内容如下:

#pragma once
#include <string>#include <Windows.h>
#include <deque>#define MAX_VIDEOPACKET_NUM 100#ifdef __cplusplus
extern "C"
{#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avutil.h"
#include "libavutil/fifo.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"#ifdef __cplusplus
};
#endifclass CVideoConvert
{public:CVideoConvert();~CVideoConvert();
public:int StartConvert(std::string strFileName, std::string strFileOut);void StopConvert();
public:int OpenFile(const char *pFile);int OpenOutPut(const char *pFileOut);
private:static DWORD WINAPI FileReadProc(LPVOID lpParam);void FileRead();static DWORD WINAPI FileWriteProc(LPVOID lpParam);void FileWrite();public:void WaitFinish();
public:AVFormatContext *m_pFormatCtx_File = NULL;AVFormatContext *m_pFormatCtx_Out = NULL;std::deque<AVPacket *> m_vecReadVideo;int m_iVideoWidth = 1920;int m_iVideoHeight = 1080;int m_iYuv420FrameSize = 0;int m_iVideoFrameNum = 0;int m_iVideoIndex = -1;bool m_bStartConvert = false;int64_t m_iTotalDuration = 0;
private:CRITICAL_SECTION m_csVideoReadSection;HANDLE m_hFileReadThread = NULL;HANDLE m_hFileWriteThread = NULL;
};

H264ToMp4.cpp里面的内容如下:

#include "H264ToMp4.h"#ifdef   __cplusplus
extern "C"
{#endif#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")#ifdef __cplusplus
};
#endifCVideoConvert::CVideoConvert()
{InitializeCriticalSection(&m_csVideoReadSection);
}CVideoConvert::~CVideoConvert()
{DeleteCriticalSection(&m_csVideoReadSection);
}int CVideoConvert::StartConvert(std::string strFileName, std::string strFileOut)
{int ret = -1;do{ret = OpenFile(strFileName.c_str());if (ret != 0){break;}ret = OpenOutPut(strFileOut.c_str());if (ret != 0){break;}if (ret < 0){break;}m_bStartConvert = true;m_hFileReadThread = CreateThread(NULL, 0, FileReadProc, this, 0, NULL);m_hFileWriteThread = CreateThread(NULL, 0, FileWriteProc, this, 0, NULL);} while (0);return ret;
}void CVideoConvert::StopConvert()
{m_bStartConvert = false;
}int CVideoConvert::OpenFile(const char *pFile)
{int ret = -1;do{if ((ret = avformat_open_input(&m_pFormatCtx_File, pFile, 0, 0)) < 0) {printf("Could not open input file.");break;}if ((ret = avformat_find_stream_info(m_pFormatCtx_File, 0)) < 0) {printf("Failed to retrieve input stream information");break;}if (m_pFormatCtx_File->nb_streams > 2){break;}for (int i = 0; i < m_pFormatCtx_File->nb_streams; i++){if (m_pFormatCtx_File->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){m_iVideoIndex = i;}}if (m_iVideoIndex == -1){break;}ret = 0;} while (0);return ret;
}int CVideoConvert::OpenOutPut(const char *pFileOut)
{int iRet = -1;AVStream *pVideoStream = NULL;do{avformat_alloc_output_context2(&m_pFormatCtx_Out, NULL, NULL, pFileOut);if (m_iVideoIndex != -1){AVCodecID eTargetVideoCodecId = m_pFormatCtx_File->streams[m_iVideoIndex]->codecpar->codec_id;AVCodec* pCodecEncode_Video = (AVCodec *)avcodec_find_encoder(eTargetVideoCodecId);pVideoStream = avformat_new_stream(m_pFormatCtx_Out, pCodecEncode_Video);if (!pVideoStream){break;}avcodec_parameters_copy(pVideoStream->codecpar, m_pFormatCtx_File->streams[m_iVideoIndex]->codecpar);pVideoStream->codecpar->codec_tag = 0;}if (!(m_pFormatCtx_Out->oformat->flags & AVFMT_NOFILE)){if (avio_open(&m_pFormatCtx_Out->pb, pFileOut, AVIO_FLAG_WRITE) < 0){break;}}if (avformat_write_header(m_pFormatCtx_Out, NULL) < 0){break;}iRet = 0;} while (0);if (iRet != 0){if (m_pFormatCtx_Out != NULL){avformat_free_context(m_pFormatCtx_Out);m_pFormatCtx_Out = NULL;}}return iRet;
}DWORD WINAPI CVideoConvert::FileReadProc(LPVOID lpParam)
{CVideoConvert *pVideoConvert = (CVideoConvert *)lpParam;if (pVideoConvert != NULL){pVideoConvert->FileRead();}return 0;
}void CVideoConvert::FileRead()
{AVPacket packet = { 0 };int ret = 0;int iPicCount = 0;const int genpts = m_pFormatCtx_File->flags & AVFMT_FLAG_GENPTS;while (m_bStartConvert){av_packet_unref(&packet);ret = av_read_frame(m_pFormatCtx_File, &packet);if (ret == AVERROR(EAGAIN)){continue;}else if (ret == AVERROR_EOF){break;}else if (ret < 0){break;}if (packet.stream_index == m_iVideoIndex){while (1){int iAudioPacketNum = m_vecReadVideo.size();if (iAudioPacketNum >= MAX_VIDEOPACKET_NUM){Sleep(10);continue;}else{AVPacket *pAudioPacket = av_packet_clone(&packet);if (pAudioPacket != NULL){EnterCriticalSection(&m_csVideoReadSection);m_vecReadVideo.push_back(pAudioPacket);LeaveCriticalSection(&m_csVideoReadSection);}}break;}}}//FlushVideoDecoder(iPicCount);
}DWORD WINAPI CVideoConvert::FileWriteProc(LPVOID lpParam)
{CVideoConvert *pVideoConvert = (CVideoConvert *)lpParam;if (pVideoConvert != NULL){pVideoConvert->FileWrite();}return 0;
}void CVideoConvert::FileWrite()
{int ret = 0;AVPacket packet = { 0 };int iRealPicCount = 0;while (m_bStartConvert){int iVideoSize = m_vecReadVideo.size();if (iVideoSize > 0){AVPacket *pPacketVideoA = NULL;EnterCriticalSection(&m_csVideoReadSection);if (!m_vecReadVideo.empty()){pPacketVideoA = m_vecReadVideo.front();m_vecReadVideo.pop_front();}LeaveCriticalSection(&m_csVideoReadSection);pPacketVideoA->stream_index = m_iVideoIndex;pPacketVideoA->duration = av_rescale_q_rnd(pPacketVideoA->duration, m_pFormatCtx_File->streams[m_iVideoIndex]->time_base, m_pFormatCtx_Out->streams[m_iVideoIndex]->time_base, AVRounding(1));if (pPacketVideoA->dts != AV_NOPTS_VALUE){pPacketVideoA->dts = av_rescale_q_rnd(pPacketVideoA->dts, m_pFormatCtx_File->streams[m_iVideoIndex]->time_base, m_pFormatCtx_Out->streams[m_iVideoIndex]->time_base, AVRounding(1));pPacketVideoA->pts = pPacketVideoA->dts;}else{pPacketVideoA->pts = pPacketVideoA->dts = m_iTotalDuration;}m_iTotalDuration += pPacketVideoA->duration;//ret = av_write_frame(m_pFormatCtx_Out, pPacketVideoA);ret = av_interleaved_write_frame(m_pFormatCtx_Out, pPacketVideoA);av_packet_free(&pPacketVideoA);if (ret == AVERROR(EAGAIN)){continue;}else if (ret == AVERROR_EOF){break;}iRealPicCount++;}else{Sleep(10);}}///FlushEncoder(iRealPicCount);av_write_trailer(m_pFormatCtx_Out);avio_close(m_pFormatCtx_Out->pb);
}void CVideoConvert::WaitFinish()
{int ret = 0;do{if (NULL == m_hFileReadThread){break;}WaitForSingleObject(m_hFileReadThread, INFINITE);CloseHandle(m_hFileReadThread);m_hFileReadThread = NULL;while (m_vecReadVideo.size() > 0){Sleep(1000);}m_bStartConvert = false;WaitForSingleObject(m_hFileWriteThread, INFINITE);CloseHandle(m_hFileWriteThread);m_hFileWriteThread = NULL;} while (0);
}

ffmpeg h264文件转mp4相关推荐

  1. H264文件封装MP4文件

    推荐一篇优秀的博文.对于MP4的初学者很有用:MP4文件格式解析_chenchong_219的博客-CSDN博客_mp4格式 对于这篇博文最后 Sample Table Box部分我想做一些补充,如有 ...

  2. 使用ffmpeg从mp4文件中提取视频流到h264文件中

    注释: -i 2018.mp4:  是输入的MP4文件 -codec copy: 从mp4中拷贝 -bsf: h264_mp4toannexb: 从mp4拷贝到annexB封装 -f h264: 采用 ...

  3. ffmpeg基础三:H264,从MP4文件获取(av_bsf_get_by_name(“h264_mp4toannexb“))和从TS流获取保存H264

    参考:零声学院 1.流媒体编解码流程 2.编码原理 在⾳视频传输过程中,视频⽂件的传输是⼀个极⼤的问题:⼀段分辨率为19201080,每个像 素点为RGB占⽤3个字节,帧率是25的视频,对于传输带宽的 ...

  4. Android多媒体:H264格式文件转MP4格式文件

    项目有Rtsp实时视频播放功能 ,现在要实现边播放边保存的功能要求.我在音视频方面技术处理白痴水平,所以 只能简单地实现先把h264格式的视频流保存到SD卡,再把对应地h264文件转码成MP4格式文件 ...

  5. 使用ffmpeg将m3u8文件转为mp4

    window环境使用ffmpeg将m3u8文件转为mp4 issue: 不存在 ffmpeg 去ffmpeg官网下载一个, 然后指派系统变量path, 我下的是https://github.com/B ...

  6. 把h264文件快速包装成mp4格式

    mkv里封装的.h264文件提取出来后,不能直接导入到premiere等视频编辑软件里,需要转换成mp4文件. 这里介绍如何把封装在 mkv 里面的 .h264 视频文件转换为 mp4 格式.(只有视 ...

  7. FFMPEG h264 ACC 合成 mkv ts;h264 mp3 合成 MP4 avi flv

    FFMPEG h264 ACC 合成 mkv ts:h264 mp3 合成 MP4 avi flv #include <stdio.h>#include <cstdio>#in ...

  8. Linux 下 ffmpeg命令行将h264文件转yuv文件

    将h264文件放到主目录下 ~$ ffmpeg -i  text.h264 -vcodec rawvideo -an out.yuv

  9. 利用FFmpeg转码生成MP4文件

    利用FFmpeg转码生成MP4文件 2017年06月24日 14:42:53 阅读数:2401 项目中,需要把一路音频流及一路视频流分别转码,生成指定格式(MP4)文件.在使用ffmpeg转码生成mp ...

最新文章

  1. 调制的缺点_电光调制与声光调制原理和应用领域
  2. link2005 重复定义错误
  3. OpenMP并行化实例----Mandelbrot集合并行化计算
  4. 五天带你学完《计算机网络》·第三天·传输层
  5. PAT甲级1089 Insert or Merge:[C++题解]插入排序、归并排序
  6. Boost:是否支持sse2指令的测试程序
  7. 分析java中文乱码的原因
  8. Linux命令集—— cat AND more
  9. java string字符拼接符+的研究
  10. 带你深入了解 GitLab CI/CD 原理及流程
  11. linux php -r,了解Linux
  12. Pycharm配置运行/调试时的工作目录
  13. 注解 @EnableFeignClients 与 @ComponentScan 有冲突
  14. bochs运行xp_bochs模拟器xp系统镜像安装教程及注意事项
  15. IAR for stm8安装破解
  16. mysql通过视图插入数据_数据库视图 sql
  17. 注册表中shell文件不见了_win10系统注册表中的shell文件不小心被删除的恢复教程...
  18. 龙之谷2服务器维护,龙之谷2今日上线!详细攻略带你玩转阿尔特里亚大陆
  19. 北师大网络教育计算机基础考试题,北京师范大学网络教育中国书法简史入学考试模拟题(单选)...
  20. Salesforce chatter:userPhotoUpload Component 使用

热门文章

  1. 人与树林交相辉映的效果
  2. Angular中nz-select实现两个选择框互相关联
  3. 包含头文件使用 书名号与双引号的区别(直接打符号竟然发表不了,太难了)
  4. 第二周python牛客练习题
  5. 【STM32】PWM 输出 (标准库)
  6. IPSEC 的IKE协商过程,主模式和野蛮模式,AH和ESP
  7. mysql版本的选择
  8. 前端:JavaScript (五)XML DOM
  9. Google封杀赛门铁克Root证书
  10. JavaScript Array数组slice方法的使用