使用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之前 代码实现相关推荐

  1. 在线短视频秒播优化之视频文件格式之MP4文件Moov box的位置

    之前我们介绍了在线短视频秒播优化的方方面面,从服务器,cdn部署接入,数据连接/获取,客户端缓存,出帧策略,到视频文件I帧位置等. 今天从视频文件格式的另外一个角度介绍,MP4文件的box排列顺序是如 ...

  2. ffmpeg源码分析及mp4文件解析

    一.mp4文件的组织 1. mp4文件的box(ffmpeg中叫atom) mp4是由一系列的box组成的,每个box的header是8个字节(4字节的长度,4字节的type) 第一个box比较特殊, ...

  3. android.process.media已停止 三星,android – 在三星设备上播放mp4文件时出现...

    我正在使用经典的VideoView实现在Android上播放视频. 相同的mp4文件网址在HTC Desire上运行正常.但它不适用于三星设备. 三星Galaxy S1和三星Galaxy Tab说:& ...

  4. 修改mp4文件的moov atom,使其位置在文件的前面

    mp4文件录制的时候,先写mdat atom对应的音视频数据,最后在尾部写上moov atom对应的一些索引信息.一些软件在录制后会再处理一次,把moov atom的位置搬到文件的前面,而把mdat ...

  5. mp4视频文件moov前置

    mp4 moov前置 原理mp4box结构 mp4信息查看工具(Mp4box.js, github) mp4box.js struct BoxHeader {uint32_t size; //4byt ...

  6. mp4文件缺少moov box无法播放情况的修复【非完美】

    一.mp4文件缺少moov box可能出现的场景有:使用录屏工具录到一半crash或断电,手机摄像机录到一般突然没电等. 二.修复的前提条件:需要有一个同样工具录制的参考视频,需要相同的mp4头部参数 ...

  7. H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    SkySeraph Apr 1st 2012 Email:skyseraph00@163.com 一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装 ...

  8. 修改MP4文件二进制内容,实现安卓Camera2旋转录制视频画面功能

    Camera2比起Camera的自定义程度更高一点,比如可以同时输出多个视频流分别用于显示预览画面和录制视频.但是!不同于Camera可以直接使用setOrientation方法直接设置视频旋转角度, ...

  9. MP4文件中h264的 SPS、PPS获取

    SkySeraph 博客园 首页 博问 闪存 新随笔 联系 订阅 管理 随笔- 190 文章- 0 评论- 407  [流媒體]H264-MP4格式及在MP4文件中提取H264的SPS.PPS及码流 ...

最新文章

  1. 【怎样写代码】小技巧 -- 关于引用类型的两种转换方式
  2. 【分块】#6283. 数列分块入门 7(区间乘法、区间加法、单点查询)
  3. collection_check_boxes的应用
  4. 运用计算机的产品设计,计算机在产品设计的应用论文
  5. 第四范式发布Sage AIOS 2.0及智能应用市场Sage App Store
  6. 微信小程序 禁止弹框下面的内容滑动 弹窗禁止底部内容滚动
  7. python的六个类型_介绍Python中6个序列的内置类型
  8. apscheduler 脚本执行失败_在脚本中使用 Bash 信号捕获 | Linux 中国
  9. 【2015.8.26】新的开始与纪念web开发
  10. 基于python的学生信息管理系统文献综述_学生信息管理系统----文献综述
  11. 关于语雀知识库的二三事
  12. linux mysql 数据恢复_怎样恢复Mysql数据库误删除后的数据
  13. 联想入选恒生指数成分股
  14. 分析案例:贷款逾期分析
  15. 泰迪云课堂大数据培训平台业务介绍
  16. vue 只要一杯卡布奇诺时间,就能简单上手的Dialog对话框
  17. linux qt3编译出错,编译ARM 平台的qt4.7.3 遇到的一些问题总结
  18. CAD图层亮度的设置
  19. 51单片机基础理论知识(会补充)
  20. 各种颜色的英文表述,以及RGB代码

热门文章

  1. 安装Flash9时,提示“Error 1904.Module的解决办法
  2. Python扑克牌程序
  3. 路由器和交换机的工作原理 2、3层
  4. 银河麒麟V10虚拟机里用virtualbox安装虚拟机
  5. 工控机上安装服务器级虚拟机vmware ESXi6.7
  6. Android之实现QQ好友分组(ExpandableListView)
  7. jsp include标签使用
  8. 密码生成器怎么用 password generator密码生成器使用教程
  9. python珠穆朗玛峰问题_学会这6招,让你的Python 嗖嗖嗖的快!
  10. 【影视源码】苹果cms时尚大气电影网站源码[自适应wap+去除授权]