iOS FFmpeg开发完全指南

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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-16 13:38
下一篇 2024-12-16 13:38

相关推荐

  • Java JsonPath 效率优化指南

    本篇文章将深入探讨Java JsonPath的效率问题,并提供一些优化方案。 一、JsonPath 简介 JsonPath是一个可用于从JSON数据中获取信息的库。它提供了一种DS…

    编程 2025-04-29
  • 运维Python和GO应用实践指南

    本文将从多个角度详细阐述运维Python和GO的实际应用,包括监控、管理、自动化、部署、持续集成等方面。 一、监控 运维中的监控是保证系统稳定性的重要手段。Python和GO都有强…

    编程 2025-04-29
  • Python wordcloud入门指南

    如何在Python中使用wordcloud库生成文字云? 一、安装和导入wordcloud库 在使用wordcloud前,需要保证库已经安装并导入: !pip install wo…

    编程 2025-04-29
  • Python应用程序的全面指南

    Python是一种功能强大而简单易学的编程语言,适用于多种应用场景。本篇文章将从多个方面介绍Python如何应用于开发应用程序。 一、Web应用程序 目前,基于Python的Web…

    编程 2025-04-29
  • Python字符转列表指南

    Python是一个极为流行的脚本语言,在数据处理、数据分析、人工智能等领域广泛应用。在很多场景下需要将字符串转换为列表,以便于操作和处理,本篇文章将从多个方面对Python字符转列…

    编程 2025-04-29
  • Python小波分解入门指南

    本文将介绍Python小波分解的概念、基本原理和实现方法,帮助初学者掌握相关技能。 一、小波变换概述 小波分解是一种广泛应用于数字信号处理和图像处理的方法,可以将信号分解成多个具有…

    编程 2025-04-29
  • Python初学者指南:第一个Python程序安装步骤

    在本篇指南中,我们将通过以下方式来详细讲解第一个Python程序安装步骤: Python的安装和环境配置 在命令行中编写和运行第一个Python程序 使用IDE编写和运行第一个Py…

    编程 2025-04-29
  • FusionMaps应用指南

    FusionMaps是一款基于JavaScript和Flash的交互式地图可视化工具。它提供了一种简单易用的方式,将复杂的数据可视化为地图。本文将从基础的配置开始讲解,到如何定制和…

    编程 2025-04-29
  • Python起笔落笔全能开发指南

    Python起笔落笔是指在编写Python代码时的编写习惯。一个好的起笔落笔习惯可以提高代码的可读性、可维护性和可扩展性,本文将从多个方面进行详细阐述。 一、变量命名 变量命名是起…

    编程 2025-04-29
  • Python中文版下载官网的完整指南

    Python是一种广泛使用的编程语言,具有简洁、易读易写等特点。Python中文版下载官网是Python学习和使用过程中的重要资源,本文将从多个方面对Python中文版下载官网进行…

    编程 2025-04-29

发表回复

登录后才能评论