一、iOS FFmpeg介绍
iOS FFmpeg是用于iOS系统的音频和视频处理库,支持各种输入格式,包括MP4、AVI、MOV等,可进行符合标准的音视频编解码、滤镜处理、转码、切割和拼接等操作。iOS FFmpeg开源、跨平台且可编译,提供了一个颇具特色的音视频开发平台。
二、iOS FFmpeg的安装与编译
准备工作:
1.下载iOS编译环境,如Xcode和Command Line Tools。
2.下载iOS FFmpeg源码,建议使用官网获取最新的稳定版本。
步骤:
1.进入下载的ffmpeg目录,执行命令:
./configure --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-doc --disable-symver
2.执行命令:
make
3.执行命令:
sudo make install
4.在工程中引用FFmpeg库,并且配置相关头文件和库文件路径。
三、iOS FFmpeg的使用
1.音频:录制、转换、编辑
使用苹果的AVFoundation库进行录音和播放,然后将音频文件导入到FFmpeg进行转换和编辑。
录制音频
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error]; [recorder record];
播放音频
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; [player play];
转换音频
AVStream *in_audio_stream, *out_audio_stream;
AVCodecContext *outAudioCodecContext;
avcodec_send_packet(in_audio_codec_context, avPacket);
avcodec_receive_frame(in_audio_codec_context, decoded_frame);
if (decoded_frame->channels > 0 && decoded_frame->channel_layout == 0) {
decoded_frame->channel_layout = av_get_default_channel_layout(decoded_frame->channels);
} else if (decoded_frame->channels == 0 && decoded_frame->channel_layout > 0) {
decoded_frame->channels = av_get_channel_layout_nb_channels(decoded_frame->channel_layout);
}
av_frame_make_writable(decoded_frame);
outAudioCodecContext->channel_layout = decoded_frame->channel_layout;
outAudioCodecContext->channels = av_get_channel_layout_nb_channels(outAudioCodecContext->channel_layout);
outAudioCodecContext->sample_rate = decoded_frame->sample_rate;
outAudioCodecContext->frame_size = decoded_frame->nb_samples;
outAudioCodecContext->sample_fmt = outAudioCodecContext->codec->sample_fmts[0];
avcodec_send_frame(outAudioCodecContext, decoded_frame);
int ret = avcodec_receive_packet(outAudioCodecContext, avPacket1);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_packet_unref(avPacket1);
return;
} else if (ret stream_index = out_audio_stream->index;
av_write_frame(formatContext, avPacket1);
av_packet_unref(avPacket);
av_packet_unref(avPacket1);
编辑音频
filter_graph = avfilter_graph_alloc();
AVFilter *src = avfilter_get_by_name("abuffer");
AVFilter *sink = avfilter_get_by_name("abuffersink");
char args[512];
snprintf(args, sizeof(args),"time_base=%d:%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, pCodecCtx->time_base.num, pCodecCtx->time_base.den, pCodecCtx->sample_rate, (
av_get_sample_fmt_name(pCodecCtx->sample_fmt)), pCodecCtx->channel_layout);
avfilter_graph_create_filter(&mosaic_filter, src, "mymosaic", args, NULL, filter_graph);
avfilter_graph_create_filter(&mosaic_sink, sink, "mymosaicout", NULL, NULL, filter_graph);
avfilter_link(mosaic_filter, 0, mosaic_sink, 0);
avfilter_graph_config(filter_graph, NULL);
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == stream_index) {
avcodec_send_packet(pCodecCtx, &packet);
while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {
av_buffersrc_add_frame_flags(mosaic_filter, pFrame, 0);
while (1) {
AVFrame *frame = av_frame_alloc();
ret = av_buffersink_get_frame(mosaic_sink, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_frame_unref(frame);
break;
}
[pcmData appendBytes:frame->data[0] length:frame->linesize[0]];
av_frame_unref(frame);
}
}
}
av_packet_unref(&packet);
}
avfilter_graph_free(&filter_graph);
2.视频:录制、转换、编辑
使用苹果的AVFoundation库进行录制和播放,然后将视频文件导入到FFmpeg进行转换和编辑。
录制视频
AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:session];
[preview setFrame:self.view.bounds];
[self.view.layer addSublayer:preview];
AVCaptureConnection *connection = videoOutput.connections[0];
if (connection.isVideoMirrored) {
connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
} else {
connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
_videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath: FilePath] fileType:AVFileTypeMPEG4 error:&error];
_videoWriterInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:_videoCompressionSettings];
[_videoWriterInput setExpectsMediaDataInRealTime:YES];
[_videoWriter addInput:_videoWriterInput];
[_videoWriter startWriting];
[_videoWriter startSessionAtSourceTime:kCMTimeZero];
[_videoWriterInput markAsFinished];
[_videoWriter finishWritingWithCompletionHandler:^{}];
播放视频
AVPlayer *player = [AVPlayer playerWithURL:someURL]; AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]; playerLayer.frame = self.view.bounds; [self.view.layer addSublayer:playerLayer]; [player play];
转换视频
AVFormatContext *pFormatCtx = NULL;
int videoindex = -1;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL, *pFrameYUV = NULL;
AVPacket *packet = NULL;
int y_size = 0;
int len = 0;
int frameGot;
int64_t in_channel_layout;
struct SwsContext *img_convert_ctx = NULL;
avcodec_register_all();
av_register_all();
_av_input_format = av_find_input_format("avfoundation");
NSString *input_str=[NSString stringWithFormat:@":%d", DEVICE_VIDEO_POSITION_BACK];
NSString *video_size = @"720x1280";//根据需求需要调整
const char *sz_input_str =[input_str UTF8String];
const char *sz_video_size = [video_size UTF8String];
av_dict_set(&_av_dict, "video_size", sz_video_size, 0);
av_dict_set(&_av_dict, "framerate", "30", 0);
if (avformat_open_input(&pFormatCtx, sz_input_str, _av_input_format, &_av_dict) != 0) {
printf("Couldn't open input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
printf("Couldn't find stream information.\n");
return -1;
}
for (int i = 0; i nb_streams; i++) {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoindex = i;
}
}
if (videoindex == -1) {
printf("Didn't find a video stream.\n");
return -1;
}
pCodecCtx = avcodec_alloc_context3(NULL);
if (!pCodecCtx) {
printf("Could not allocate AVCodecContext.\n");
return -1;
}
avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoindex]->codecpar);
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (!pCodec) {
printf("Failed to find codec.\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) width * pCodecCtx->height;
av_image_alloc(pFrameYUV->data, pFrameYUV->linesize, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, 16);
packet = (AVPacket *)av_malloc(sizeof(AVPacket));
while (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet->stream_index == videoindex) {
avcodec_send_packet(pCodecCtx, packet);
while (1) {
frameGot = avcodec_receive_frame(pCodecCtx, pFrame);
if (frameGot != 0) {
break;
}
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
len = fwrite(pFrameYUV->data[0], 1, y_size * 3 / 2, dst_fd);
}
}
av_packet_unref(packet);
}
av_packet_free(&packet);
av_frame_free(&pFrame);
av_frame_free(&pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
av_dict_free(&_av_dict);
编辑视频
AVFormatContext *inputFormatContext = avformat_alloc_context();
AVFormatContext *outputFormatContext = avformat_alloc_context();
AVOutputFormat *outputFormat = NULL;
AVStream *inputStream = NULL, *outputStream = NULL;;
AVCodecContext *inputCodecContext = NULL, *outputCodecContext = NULL;
AVCodec *inputCodec = NULL, *outputCodec = NULL;
AVPacket *criticalPacket = NULL, *outputPacket = NULL;
AVFrame *inputFrame = NULL, *outputFrame = NULL;
uint8_t *outputBuffer = NULL;
int frameFinished = 0, outputBufferSize, outputFrameCount = 0;av_register_all();
avformat_network_init();if (avformat_open_input(&inputFormatContext, [inputUrl.absoluteString UTF8String], NULL, NULL) < 0) {
printf("Could not open input file.\n");
[self setMovieDuration:kCMTimeZero];
AVCaptureConnection *connection = _videoOutput.connections[0];
connection.videoOrientation = AVCaptureVideoOrientationPortrait;
return;
}if (avformat_find_stream_info(inputFormatContext, NULL) < 0) {
printf("Could not find stream information.\n");
[self setMovieDuration:kCMTimeZero];
AVCaptureConnection *connection = _videoOutput.connections[0];
connection.videoOrientation = AVCaptureVideoOrientationPortrait;
return;
}if (av_find_best_stream(inputFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &inputCodec, 0) streams[inputCodec->index]->codec;
inputStream = inputFormatContext->streams[inputCodecContext->time_base.num == 0 ? 1 : 0];
outputFormat = av_guess_format("mp4", "video.mp4", NULL);
if (outputFormat == NULL) {
printf("Could not guess output format.\n");
return;
}if (avformat_alloc_output_context2(&outputFormatContext, outputFormat, NULL, NULL) id);
outputCodecContext = avcodec_alloc_context3(outputCodec);if (outputCodecContext == NULL) {
printf("Could not allocate codec context.\n");
return;
}outputStream->codec = outputCodecContext;
if (avcodec_open2(outputCodecContext, outputCodec, NULL) oformat->flags & AVFMT_GLOBALHEADER) {
outputCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/270833.html
微信扫一扫
支付宝扫一扫