一、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