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

来源:互联网 发布:淘宝好的名牌原单店 编辑:程序博客网 时间:2024/05/23 01:40
/** *每次从H.264文件读取IO_BUFFER_SIZE字节的数据, *模拟输入H.264流,最终输出封装格式文件。 */#include "stdafx.h"#define __STDC_CONSTANT_MACROSextern "C"{#include "libavformat/avformat.h"}#define IO_BUFFER_SIZE 32768int main(int argc, char* argv[]){//const char *in_filename_v = argv[1]; //Input file URL//const char *out_filename = argv[2]; //Output file URLconst char *in_filename_v = "media files/JINUSEAN_17s.h264"; //Input file URLconst char *out_filename = "media files/JINUSEAN_17s.mkv"; //Output file URLAVOutputFormat *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 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;//Write file headerif (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);//Parameterspkt.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 trailerav_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;}

0 0
原创粉丝点击