此文旨在拋磚引玉 跟同道交流學(xué)習(xí)
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavcodec/avcodec.h>
int WIDTH=320;
int HEIGHT=240;
int FPS=30;
int BITRATE=16*1000;
@interface ConvertToMov ()
{
//Input AVFormatContext and Output AVFormatContext
AVOutputFormat *outFormat;
AVFormatContext *outfmt_ctx;
NSString *movBasePath;
NSString *filePath;
}
@end
@implementation ConvertToMov
-(id)init
{
self = [super init];
if (self)
{
[self setup];
}
return self;
}
-(void)setup
{
movBasePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
//保存幀數(shù)據(jù)
-(void)procWithData:(NSData *)data
{
int ret;
AVPacket avPacket;
av_init_packet(&avPacket);
avPacket.data = (uint8_t *)[data bytes];
avPacket.size = (int)data.length;
avPacket.pos = -1;
ret = av_interleaved_write_frame(outfmt_ctx, &avPacket);//寫入(Write)
if (ret < 0)
{
DLog(@ "Error muxing packet\n");
}
//Write
if (av_interleaved_write_frame(outfmt_ctx, &avPacket) < 0)
{
DLog(@ "Error muxing packet\n");
}
av_free_packet(&avPacket);
}
//寫入頭信息
-(void)start
{
int ret;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSCalendar *curCalendar = [NSCalendar currentCalendar];
NSUInteger unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *dateComponents = [curCalendar components:unitFlags fromDate:[NSDate date]];
filePath = [movBasePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%ld-%ld-%ld.mp4",(long)dateComponents.hour, (long)dateComponents.minute, (long)dateComponents.second ]];
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
const char *out_filename = [filePath UTF8String];//URL 路徑
av_register_all();//注冊所有容器格式和CODEC
avformat_alloc_output_context2(&outfmt_ctx, NULL, "mp4", out_filename);// 初始化一個(gè)用于輸出的AVFormatContext結(jié)構(gòu)體
if (!outfmt_ctx)
{
DLog(@ "Could not create output context\n");
// ret = AVERROR_UNKNOWN;
}
outFormat = outfmt_ctx->oformat;
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);//查找對應(yīng)的解碼器
AVStream *out_stream = avformat_new_stream(outfmt_ctx, codec);//創(chuàng)建輸出碼流的AVStream
if (!out_stream)
{
DLog(@ "Failed allocating output stream\n");
// ret = AVERROR_UNKNOWN;
}
ret = avcodec_copy_context(out_stream->codec, avcodec_alloc_context3(codec));//拷貝輸入視頻碼流的AVCodecContex的數(shù)值t到輸出視頻的AVCodecContext榛臼。
if (ret < 0)
{
DLog(@ "Failed to copy context from input to output stream codec context\n");
}
out_stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;//支持的像素格式
out_stream->codec->flags = CODEC_FLAG_GLOBAL_HEADER;
out_stream->codec->width = WIDTH;
out_stream->codec->height = HEIGHT;
out_stream->codec->time_base = (AVRational){1,FPS};
out_stream->codec->gop_size = FPS;
out_stream->codec->bit_rate = BITRATE;
out_stream->codec->codec_tag = 0;
if (outfmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
{
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
// AVBitStreamFilterContext \*avFilter = av_bitstream_filter_init("h264_mp4toannexb");
// out_stream->codec->extradata_size = size;
// out_stream->codec->extradata = (uint8_t \*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
//輸出一下格式------------------
av_dump_format(outfmt_ctx, 0, out_filename, 1);
if (!(outFormat->flags & AVFMT_NOFILE))
{
ret = avio_open(&outfmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0)
{
DLog(@ "Could not open output file '%s'", out_filename);
}
}
//寫文件頭(Write file header)
ret = avformat_write_header(outfmt_ctx, NULL);
if (ret < 0)
{
DLog(@ "Error occurred when opening output file\n");
}
}
//寫入尾信息
-(void)stop
{
av_write_trailer(outfmt_ctx);
}
-(void)clean
{
if (outfmt_ctx && !(outFormat->flags & AVFMT_NOFILE))
{
avio_close(outfmt_ctx->pb);
}
avformat_free_context(outfmt_ctx);
}
@end