mp4文件moov atom放置在mdat atom之前 代码实现
使用nginx搭建http mp4/flv流媒体服务器,要求mp4文件moov atom要放置在mdat atom前,才能边下载边播放。参考php-qtfaststart项目,测试代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>#ifdef __MINGW32__
#define fseeko(x, y, z) fseeko64(x, y, z)
#define ftello(x) ftello64(x)
#endif#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \(((uint8_t*)(x))[1] << 16) | \(((uint8_t*)(x))[2] << 8) | \((uint8_t*)(x))[3])#define BE_64(x) (((uint64_t)(((uint8_t*)(x))[0]) << 56) | \((uint64_t)(((uint8_t*)(x))[1]) << 48) | \((uint64_t)(((uint8_t*)(x))[2]) << 40) | \((uint64_t)(((uint8_t*)(x))[3]) << 32) | \((uint64_t)(((uint8_t*)(x))[4]) << 24) | \((uint64_t)(((uint8_t*)(x))[5]) << 16) | \((uint64_t)(((uint8_t*)(x))[6]) << 8) | \((uint64_t)( (uint8_t*)(x))[7]))#define BE_FOURCC(ch0, ch1, ch2, ch3) \( (uint32_t)(unsigned char)(ch3) | \((uint32_t)(unsigned char)(ch2) << 8) | \((uint32_t)(unsigned char)(ch1) << 16) | \((uint32_t)(unsigned char)(ch0) << 24) )#define QT_ATOM BE_FOURCC
/* top level atoms */
#define FREE_ATOM QT_ATOM('f', 'r', 'e', 'e')
#define JUNK_ATOM QT_ATOM('j', 'u', 'n', 'k')
#define MDAT_ATOM QT_ATOM('m', 'd', 'a', 't')
#define MOOV_ATOM QT_ATOM('m', 'o', 'o', 'v')
#define PNOT_ATOM QT_ATOM('p', 'n', 'o', 't')
#define SKIP_ATOM QT_ATOM('s', 'k', 'i', 'p')
#define WIDE_ATOM QT_ATOM('w', 'i', 'd', 'e')
#define PICT_ATOM QT_ATOM('P', 'I', 'C', 'T')
#define FTYP_ATOM QT_ATOM('f', 't', 'y', 'p')
#define UUID_ATOM QT_ATOM('u', 'u', 'i', 'd')#define CMOV_ATOM QT_ATOM('c', 'm', 'o', 'v')
#define STCO_ATOM QT_ATOM('s', 't', 'c', 'o')
#define CO64_ATOM QT_ATOM('c', 'o', '6', '4')#define ATOM_PREAMBLE_SIZE 8
#define COPY_BUFFER_SIZE 1024int do_faststart(char *in, char *out)
{FILE *infile = NULL;FILE *outfile = NULL;unsigned char atom_bytes[ATOM_PREAMBLE_SIZE];uint32_t atom_type = 0;uint64_t atom_size = 0;uint64_t atom_offset = 0;uint64_t last_offset;unsigned char *moov_atom = NULL;unsigned char *ftyp_atom = NULL;uint64_t moov_atom_size;uint64_t ftyp_atom_size = 0;uint64_t i, j;uint32_t offset_count;uint64_t current_offset;uint64_t start_offset = 0;
uint64_t moov_offset = 0;
uint64_t moov_size = 0;
uint64_t mdat_offset = 0;
uint64_t mdat_size = 0;unsigned char copy_buffer[COPY_BUFFER_SIZE];int bytes_to_copy;infile = fopen(in, "rb");if (!infile) {//perror(in);goto error_out;}/* traverse through the atoms in the file to make sure that 'moov' is* at the end */while (!feof(infile)) {if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {break;}atom_size = (uint32_t) BE_32(&atom_bytes[0]);atom_type = BE_32(&atom_bytes[4]);/* keep ftyp atom */if (atom_type == FTYP_ATOM) {ftyp_atom_size = atom_size;free(ftyp_atom);ftyp_atom = malloc(ftyp_atom_size);if (!ftyp_atom) {//printf("could not allocate %"PRIu64" bytes for ftyp atom\n",atom_size);goto error_out;}fseeko(infile, -ATOM_PREAMBLE_SIZE, SEEK_CUR);if (fread(ftyp_atom, atom_size, 1, infile) != 1) {//perror(in);goto error_out;}start_offset = ftello(infile);} else {/* 64-bit special case */if (atom_size == 1) {if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {break;}atom_size = BE_64(&atom_bytes[0]);fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE * 2, SEEK_CUR);} else {fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE, SEEK_CUR);}}printf("%c%c%c%c %10"PRIu64" %"PRIu64"\n",(atom_type >> 24) & 255,(atom_type >> 16) & 255,(atom_type >> 8) & 255,(atom_type >> 0) & 255,atom_offset,atom_size);if(atom_type == MOOV_ATOM){moov_offset = atom_offset;moov_size = atom_size;
}else if(atom_type == MDAT_ATOM){mdat_offset = atom_offset;mdat_size = atom_size;
}if ((atom_type != FREE_ATOM) &&(atom_type != JUNK_ATOM) &&(atom_type != MDAT_ATOM) &&(atom_type != MOOV_ATOM) &&(atom_type != PNOT_ATOM) &&(atom_type != SKIP_ATOM) &&(atom_type != WIDE_ATOM) &&(atom_type != PICT_ATOM) &&(atom_type != UUID_ATOM) &&(atom_type != FTYP_ATOM)) {//printf("encountered non-QT top-level atom (is this a QuickTime file?)\n");break;}atom_offset += atom_size;/* The atom header is 8 (or 16 bytes), if the atom size (which* includes these 8 or 16 bytes) is less than that, we won't be* able to continue scanning sensibly after this atom, so break. */if (atom_size < 8)break;}/*if (atom_type != MOOV_ATOM) {printf("last atom in file was not a moov atom\n");free(ftyp_atom);fclose(infile);return 0;}*/if(moov_offset < mdat_offset){
printf("moov atom is before in mdat atom\n");free(ftyp_atom);fclose(infile);return 0;
}if(moov_offset == 0 || moov_size == 0){
printf("don't found moov atom in file\n");free(ftyp_atom);fclose(infile);return 0;
}/* moov atom was, in fact, the last atom in the chunk; load the whole* moov atom *///fseeko(infile, -atom_size, SEEK_END);
fseeko(infile, moov_offset, SEEK_SET);
printf("seek to moov atom:%x\n",moov_offset);last_offset = ftello(infile);//moov_atom_size = atom_size;
moov_atom_size = moov_size;moov_atom = malloc(moov_atom_size);if (!moov_atom) {//printf("could not allocate %"PRIu64" bytes for moov atom\n", atom_size);goto error_out;}if (fread(moov_atom, moov_atom_size, 1, infile) != 1) {//perror(in);goto error_out;}/* this utility does not support compressed atoms yet, so disqualify* files with compressed QT atoms */if (BE_32(&moov_atom[12]) == CMOV_ATOM) {//printf("this utility does not support compressed moov atoms yet\n");goto error_out;}/* close; will be re-opened later */fclose(infile);infile = NULL;/* crawl through the moov chunk in search of stco or co64 atoms */for (i = 4; i < moov_atom_size - 4; i++) {atom_type = BE_32(&moov_atom[i]);if (atom_type == STCO_ATOM) {printf(" patching stco atom...\n");atom_size = BE_32(&moov_atom[i - 4]);if (i + atom_size - 4 > moov_atom_size) {//printf(" bad atom size\n");goto error_out;}offset_count = BE_32(&moov_atom[i + 8]);for (j = 0; j < offset_count; j++) {current_offset = BE_32(&moov_atom[i + 12 + j * 4]);current_offset += moov_atom_size;moov_atom[i + 12 + j * 4 + 0] = (current_offset >> 24) & 0xFF;moov_atom[i + 12 + j * 4 + 1] = (current_offset >> 16) & 0xFF;moov_atom[i + 12 + j * 4 + 2] = (current_offset >> 8) & 0xFF;moov_atom[i + 12 + j * 4 + 3] = (current_offset >> 0) & 0xFF;}i += atom_size - 4;} else if (atom_type == CO64_ATOM) {printf(" patching co64 atom...\n");atom_size = BE_32(&moov_atom[i - 4]);if (i + atom_size - 4 > moov_atom_size) {//printf(" bad atom size\n");goto error_out;}offset_count = BE_32(&moov_atom[i + 8]);for (j = 0; j < offset_count; j++) {current_offset = BE_64(&moov_atom[i + 12 + j * 8]);current_offset += moov_atom_size;moov_atom[i + 12 + j * 8 + 0] = (current_offset >> 56) & 0xFF;moov_atom[i + 12 + j * 8 + 1] = (current_offset >> 48) & 0xFF;moov_atom[i + 12 + j * 8 + 2] = (current_offset >> 40) & 0xFF;moov_atom[i + 12 + j * 8 + 3] = (current_offset >> 32) & 0xFF;moov_atom[i + 12 + j * 8 + 4] = (current_offset >> 24) & 0xFF;moov_atom[i + 12 + j * 8 + 5] = (current_offset >> 16) & 0xFF;moov_atom[i + 12 + j * 8 + 6] = (current_offset >> 8) & 0xFF;moov_atom[i + 12 + j * 8 + 7] = (current_offset >> 0) & 0xFF;}i += atom_size - 4;}}/* re-open the input file and open the output file */infile = fopen(in, "rb");if (!infile) {//perror(in);goto error_out;}if (start_offset > 0) { /* seek after ftyp atom */fseeko(infile, start_offset, SEEK_SET);last_offset -= start_offset;}fseeko(infile, start_offset, SEEK_SET);outfile = fopen(out, "wb");if (!outfile) {//perror(out);goto error_out;}/* dump the same ftyp atom */if (ftyp_atom_size > 0) {//printf(" writing ftyp atom...\n");if (fwrite(ftyp_atom, ftyp_atom_size, 1, outfile) != 1) {//perror(out);goto error_out;}}/* dump the new moov atom *///printf(" writing moov atom...\n");if (fwrite(moov_atom, moov_atom_size, 1, outfile) != 1) {//perror(out);goto error_out;}/* copy the remainder of the infile, from offset 0 -> last_offset - 1 *///printf(" copying rest of file...\n");while (last_offset) {if (last_offset > COPY_BUFFER_SIZE)bytes_to_copy = COPY_BUFFER_SIZE;elsebytes_to_copy = last_offset;if (fread(copy_buffer, bytes_to_copy, 1, infile) != 1) {//perror(in);goto error_out;}if (fwrite(copy_buffer, bytes_to_copy, 1, outfile) != 1) {//perror(out);goto error_out;}last_offset -= bytes_to_copy;}fclose(infile);fclose(outfile);free(moov_atom);free(ftyp_atom);return 0;error_out:
printf("transcode %s to %s failed.\n",in, out);if (infile)fclose(infile);if (outfile)fclose(outfile);free(moov_atom);free(ftyp_atom);return 1;
}int main(int argc, char *argv[])
{if (argc != 3) {printf("Usage: qt-faststart <infile.mov> <outfile.mov>\n");return 0;}if (!strcmp(argv[1], argv[2])) {fprintf(stderr, "input and output files need to be different\n");return 1;}return do_faststart(argv[1],argv[2]);
}
mp4文件moov atom放置在mdat atom之前 代码实现相关推荐
- 在线短视频秒播优化之视频文件格式之MP4文件Moov box的位置
之前我们介绍了在线短视频秒播优化的方方面面,从服务器,cdn部署接入,数据连接/获取,客户端缓存,出帧策略,到视频文件I帧位置等. 今天从视频文件格式的另外一个角度介绍,MP4文件的box排列顺序是如 ...
- ffmpeg源码分析及mp4文件解析
一.mp4文件的组织 1. mp4文件的box(ffmpeg中叫atom) mp4是由一系列的box组成的,每个box的header是8个字节(4字节的长度,4字节的type) 第一个box比较特殊, ...
- android.process.media已停止 三星,android – 在三星设备上播放mp4文件时出现...
我正在使用经典的VideoView实现在Android上播放视频. 相同的mp4文件网址在HTC Desire上运行正常.但它不适用于三星设备. 三星Galaxy S1和三星Galaxy Tab说:& ...
- 修改mp4文件的moov atom,使其位置在文件的前面
mp4文件录制的时候,先写mdat atom对应的音视频数据,最后在尾部写上moov atom对应的一些索引信息.一些软件在录制后会再处理一次,把moov atom的位置搬到文件的前面,而把mdat ...
- mp4视频文件moov前置
mp4 moov前置 原理mp4box结构 mp4信息查看工具(Mp4box.js, github) mp4box.js struct BoxHeader {uint32_t size; //4byt ...
- mp4文件缺少moov box无法播放情况的修复【非完美】
一.mp4文件缺少moov box可能出现的场景有:使用录屏工具录到一半crash或断电,手机摄像机录到一般突然没电等. 二.修复的前提条件:需要有一个同样工具录制的参考视频,需要相同的mp4头部参数 ...
- H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
SkySeraph Apr 1st 2012 Email:skyseraph00@163.com 一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装 ...
- 修改MP4文件二进制内容,实现安卓Camera2旋转录制视频画面功能
Camera2比起Camera的自定义程度更高一点,比如可以同时输出多个视频流分别用于显示预览画面和录制视频.但是!不同于Camera可以直接使用setOrientation方法直接设置视频旋转角度, ...
- MP4文件中h264的 SPS、PPS获取
SkySeraph 博客园 首页 博问 闪存 新随笔 联系 订阅 管理 随笔- 190 文章- 0 评论- 407 [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 ...
最新文章
- 【怎样写代码】小技巧 -- 关于引用类型的两种转换方式
- 【分块】#6283. 数列分块入门 7(区间乘法、区间加法、单点查询)
- collection_check_boxes的应用
- 运用计算机的产品设计,计算机在产品设计的应用论文
- 第四范式发布Sage AIOS 2.0及智能应用市场Sage App Store
- 微信小程序 禁止弹框下面的内容滑动 弹窗禁止底部内容滚动
- python的六个类型_介绍Python中6个序列的内置类型
- apscheduler 脚本执行失败_在脚本中使用 Bash 信号捕获 | Linux 中国
- 【2015.8.26】新的开始与纪念web开发
- 基于python的学生信息管理系统文献综述_学生信息管理系统----文献综述
- 关于语雀知识库的二三事
- linux mysql 数据恢复_怎样恢复Mysql数据库误删除后的数据
- 联想入选恒生指数成分股
- 分析案例:贷款逾期分析
- 泰迪云课堂大数据培训平台业务介绍
- vue 只要一杯卡布奇诺时间,就能简单上手的Dialog对话框
- linux qt3编译出错,编译ARM 平台的qt4.7.3 遇到的一些问题总结
- CAD图层亮度的设置
- 51单片机基础理论知识(会补充)
- 各种颜色的英文表述,以及RGB代码
热门文章
- 安装Flash9时,提示“Error 1904.Module的解决办法
- Python扑克牌程序
- 路由器和交换机的工作原理 2、3层
- 银河麒麟V10虚拟机里用virtualbox安装虚拟机
- 工控机上安装服务器级虚拟机vmware ESXi6.7
- Android之实现QQ好友分组(ExpandableListView)
- jsp include标签使用
- 密码生成器怎么用 password generator密码生成器使用教程
- python珠穆朗玛峰问题_学会这6招,让你的Python 嗖嗖嗖的快!
- 【影视源码】苹果cms时尚大气电影网站源码[自适应wap+去除授权]