模拟输入H.264流,输出封装格式文件
2015-11-16 18:15
393 查看
/** *每次从H.264文件读取IO_BUFFER_SIZE字节的数据, *模拟输入H.264流,最终输出封装格式文件。 */ #include "stdafx.h" #define __STDC_CONSTANT_MACROS extern "C" { #include "libavformat/avformat.h" } #define IO_BUFFER_SIZE 32768 int main(int argc, char* argv[]) { //const char *in_filename_v = argv[1]; //Input file URL //const char *out_filename = argv[2]; //Output file URL const char *in_filename_v = "media files/JINUSEAN_17s.h264"; //Input file URL const char *out_filename = "media files/JINUSEAN_17s.mkv"; //Output file URL AVOutputFormat *ofmt = NULL; AVFormatContext *ofmt_ctx = NULL; int ret; FILE *fp_open; fp_open = fopen(in_filename_v, "rb+"); 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 file if (!(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; //Write file header if (avformat_write_header(ofmt_ctx, NULL) < 0) { printf("Error occurred when opening output file\n"); goto end; } out_stream->r_frame_rate.num = 30000; out_stream->r_frame_rate.den = 1001; //temp为临时缓冲区,存储上一次传入数据剩余的不完整帧和本次传入的数据。 uint8_t *temp = (uint8_t *)malloc(4 * IO_BUFFER_SIZE); //上一次传入数据剩余的不完整帧的大小。 int residue_len = 0; int frame_index = 0; for (int i = 0; i < 200; i++) { uint8_t *buf = (uint8_t *)malloc(IO_BUFFER_SIZE); fread(buf, 1, IO_BUFFER_SIZE, fp_open); memcpy(temp + residue_len, buf, IO_BUFFER_SIZE); int frame_header = 0; //之所以从j==1开始,是因为j==0必然是帧头,现在要找的是下一个帧头 for (int j = 1; j <= residue_len + IO_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_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 = out_stream->time_base; //Duration between 2 frames (μs) int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(out_stream->r_frame_rate); //Parameters pkt.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base)*AV_TIME_BASE); pkt.dts = pkt.pts; 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"); break; } av_free_packet(&pkt); frame_header = j; } else { continue; } } residue_len = residue_len + IO_BUFFER_SIZE - frame_header; //即使有重叠区域,也允许这样进行内存拷贝,要拷贝的尾部数据会覆盖temp+frame_header以后的重叠区域。 memcpy(temp, temp + frame_header, residue_len); free(buf); } free(temp); //Write file trailer av_write_trailer(ofmt_ctx); end: /* close output */ if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) avio_close(ofmt_ctx->pb); avformat_free_context(ofmt_ctx); fclose(fp_open); return 0; }
相关文章推荐
- Managed Media Aggregation using Rtsp and Rtp
- 利用Ffmpeg获得flv视频缩略图和视频时间的代码
- codeigniter教程之上传视频并使用ffmpeg转flv示例
- PHP使用ffmpeg给视频增加字幕显示的方法
- PHP+FFMPEG实现将视频自动转码成H264标准Mp4文件
- 快速解决Android平台移植ffmpeg的一些问题
- java调用ffmpeg实现视频转换的方法
- python+ffmpeg视频并发直播压力测试
- [总结]FFMPEG视音频编解码零基础学习方法
- CentOs 下安装 ffmpeg 以及添加 ogg 音频支持
- FFmpeg音视频编解码实践总结
- ffmpeg 视频压缩 转换
- linux ffmpeg编译配置安装详解
- 解密FFmpeg播放track mode控制
- [学习与生活]视频开发网
- FFMPEG SDK 开发介绍
- 欠揍的ffmpeg,调试android里的ffmpeg (1)
- Android NDK r8b 和 FFmpeg 0.11.2 移植
- HelloWorld App of ffmpeg JNI
- XCode5下编译iOS7的lua,openssl,curl,libuv,ffmpeg库