在xcode上開發
//param splitSeconds 為視頻分割的時長
+ (BOOL)executeSplit:(unsignedint)splitSeconds {
? ? AVFormatContext*ifmtCtx,*ofmtCtx;
? ? charconst? ? ? *inputFileName, *outputFileName;
? ? int? ? ? ? ? ? video_index;
? ? inputFileName = [[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp4"] UTF8String];
? ? outputFileName ="/Users/ubaby/Library/Containers/bylh.testFFmpegOS/Data/Documents/test0.mp4";
? ? AVPacketreadPkt, splitKeyPacket;
? ? intret;
? ? av_register_all();
? ? if((ret =avformat_open_input(&ifmtCtx, inputFileName,0,0)) <0) {
? ? ? ? return false;
? ? }
? ? if((ret =avformat_find_stream_info(ifmtCtx,0)) <0) {
? ? ? ? return false;
? ? }
? ? for(inti =0; i < ifmtCtx->nb_streams; i++) {
? ? ? ? AVStream*in_stream = ifmtCtx->streams[i];
? ? ? ? if(in_stream->codec->codec_type==AVMEDIA_TYPE_VIDEO){
? ? ? ? ? ? video_index = i;
? ? ? ? }
? ? }
? ? intden = ifmtCtx->streams[video_index]->r_frame_rate.den;
? ? intnum = ifmtCtx->streams[video_index]->r_frame_rate.num;
? ? floatfps = (float)num / den;
? ? unsignedintsplitVideoSize = fps*splitSeconds;
? ? charconst? ? ? *save_name = outputFileName;
? ? charconst? ? ? *temp_name = save_name;
? ? avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, temp_name);
? ? if(!ofmtCtx) {
? ? ? ? return false;
? ? }
? ? if (![testVideo writeVideoHeader:ifmtCtx out_filename:ofmtCtx out_filename:temp_name])
? ? {
? ? ? ? return false;
? ? }
? ? NSMutableArray *vecKeyFramePos = [NSMutableArray arrayWithCapacity:1];
? ? uint64_tframe_index =0;
? ? uint64_tkeyFrame_index =0;
? ? intframeCount =0;
? ? //讀取分割點附近的關鍵幀位置
? ? while(1)
? ? {
? ? ? ? ++frame_index;
? ? ? ? ret =av_read_frame(ifmtCtx, &readPkt);
? ? ? ? if(ret <0)
? ? ? ? {
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? //過濾,只處理視頻流
? ? ? ? if(readPkt.stream_index== video_index){
? ? ? ? ? ? ++frameCount;
? ? ? ? ? ? if(readPkt.flags&AV_PKT_FLAG_KEY)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? keyFrame_index = frame_index;
? ? ? ? ? ? }
? ? ? ? ? ? if(frameCount==splitVideoSize)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //? ? ? ? ? ? ? ? vecKeyFramePos.push_back(keyFrame_index);
? ? ? ? ? ? ? ? [vecKeyFramePosaddObject:[NSNumbernumberWithUnsignedLongLong:keyFrame_index]];
? ? ? ? ? ? ? ? frameCount =0;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? av_packet_unref(&readPkt);
? ? }
? ? avformat_close_input(&ifmtCtx);
? ? ifmtCtx =NULL;
? ? //為了重新獲取avformatcontext
? ? if((ret =avformat_open_input(&ifmtCtx, inputFileName,0,0)) <0) {
? ? ? ? return-1;
? ? }
? ? if((ret =avformat_find_stream_info(ifmtCtx,0)) <0) {
? ? ? ? return-1;
? ? }
? ? intnumber =0;
? ? av_init_packet(&splitKeyPacket);
? ? splitKeyPacket.data=NULL;
? ? splitKeyPacket.size=0;
? ? //時長對應的幀數超過視頻的總視頻幀數,則拷貝完整視頻
? ? if(!vecKeyFramePos.count){
? ? ? ? [vecKeyFramePosaddObject:[NSNumbernumberWithUnsignedLongLong:frame_index]];
? ? }
? ? keyFrame_index = [[vecKeyFramePosfirstObject]unsignedLongLongValue];
? ? NSUIntegerkeyFrameIter =1;
? ? frame_index =0;
? ? int64_tlastPts =0;
? ? int64_tlastDts =0;
? ? int64_tprePts =0;
? ? int64_tpreDts =0;
? ? while(1)
? ? {
? ? ? ? ++frame_index;
? ? ? ? ret =av_read_frame(ifmtCtx, &readPkt);
? ? ? ? if(ret <0)
? ? ? ? {
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? av_packet_rescale_ts(&readPkt, ifmtCtx->streams[readPkt.stream_index]->time_base, ofmtCtx->streams[readPkt.stream_index]->time_base);
? ? ? ? prePts = readPkt.pts;
? ? ? ? preDts = readPkt.dts;
? ? ? ? readPkt.pts-= lastPts;
? ? ? ? readPkt.dts-= lastDts;
? ? ? ? if(readPkt.pts< readPkt.dts)
? ? ? ? {
? ? ? ? ? ? readPkt.pts= readPkt.dts+1;
? ? ? ? }
? ? ? ? //為分割點處的關鍵幀要進行拷貝
? ? ? ? if(readPkt.flags&AV_PKT_FLAG_KEY&&frame_index == keyFrame_index)
? ? ? ? {
? ? ? ? ? ? av_copy_packet(&splitKeyPacket, &readPkt);
? ? ? ? }
? ? ? ? else{
? ? ? ? ? ? ret =av_interleaved_write_frame(ofmtCtx, &readPkt);
? ? ? ? ? ? if(ret <0) {
? ? ? ? ? ? ? ? //break;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(frame_index == keyFrame_index)
? ? ? ? {
? ? ? ? ? ? lastDts = preDts;
? ? ? ? ? ? lastPts = prePts;
? ? ? ? ? ? if(keyFrameIter < vecKeyFramePos.count)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? keyFrame_index = [vecKeyFramePos[keyFrameIter]unsignedLongLongValue];
? ? ? ? ? ? ? ? keyFrameIter++;
? ? ? ? ? ? }
? ? ? ? ? ? av_write_trailer(ofmtCtx);
? ? ? ? ? ? avio_close(ofmtCtx->pb);
? ? ? ? ? ? avformat_free_context(ofmtCtx);
? ? ? ? ? ? ++number;
? ? ? ? ? ? NSString *tempStr = [NSString stringWithFormat:@"/Users/ubaby/Library/Containers/bylh.testFFmpegOS/Data/Documents/test%d.mp4",number];
? ? ? ? ? ? NSLog(@"===========%@",tempStr);
? ? ? ? ? ? temp_name = [tempStrUTF8String];
? ? ? ? ? ? avformat_alloc_output_context2(&ofmtCtx,NULL,NULL, temp_name);
? ? ? ? ? ? if(!ofmtCtx) {
? ? ? ? ? ? ? ? returnfalse;
? ? ? ? ? ? }
? ? ? ? ? ? if(![testVideowriteVideoHeader:ifmtCtxout_filename:ofmtCtxout_filename:temp_name])
? ? ? ? ? ? {
? ? ? ? ? ? ? ? returnfalse;
? ? ? ? ? ? }
? ? ? ? ? ? splitKeyPacket.pts=0;
? ? ? ? ? ? splitKeyPacket.dts=0;
? ? ? ? ? ? //把上一個分片處的關鍵幀寫入到下一個分片的起始處,保證下一個分片的開頭為I幀
? ? ? ? ? ? ret =av_interleaved_write_frame(ofmtCtx, &splitKeyPacket);
? ? ? ? }
? ? ? ? av_packet_unref(&readPkt);
? ? }
? ? av_packet_unref(&splitKeyPacket);
? ? av_write_trailer(ofmtCtx);
? ? avformat_close_input(&ifmtCtx);
? ? avio_close(ofmtCtx->pb);
? ? avformat_free_context(ofmtCtx);
? ? return true;
}
+ (BOOL)writeVideoHeader:(AVFormatContext*)ifmtCtx out_filename:(AVFormatContext*)ofmtCtx out_filename:(charconst*)out_filename
{
? ? AVOutputFormat *ofmt = NULL;
? ? intret;
? ? int? ? ? ? ? ? video_index;
? ? ofmt = ofmtCtx->oformat;
? ? for(inti =0; i < ifmtCtx->nb_streams; i++) {
? ? ? ? //∏????‰????¥¥Ω??‰≥???£?Create output AVStream according to input AVStream£?
? ? ? ? AVStream*in_stream = ifmtCtx->streams[i];
? ? ? ? if(in_stream->codec->codec_type==AVMEDIA_TYPE_VIDEO){
? ? ? ? ? ? video_index = i;
? ? ? ? }
? ? ? ? AVStream*out_stream =avformat_new_stream(ofmtCtx, in_stream->codec->codec);
? ? ? ? if(!out_stream) {
? ? ? ? ? ? ret =AVERROR_UNKNOWN;
? ? ? ? ? ? returnfalse;
? ? ? ? }
? ? ? ? //∏¥÷?AVCodecContextμ?…?÷√£?Copy the settings of AVCodecContext£?
? ? ? ? ret =avcodec_copy_context(out_stream->codec, in_stream->codec);
? ? ? ? if(ret <0) {
? ? ? ? ? ? returnfalse;
? ? ? ? }
? ? ? ? out_stream->codec->codec_tag=0;
? ? ? ? if(ofmtCtx->oformat->flags&AVFMT_GLOBALHEADER)
? ? ? ? ? ? out_stream->codec->flags|=AV_CODEC_FLAG_GLOBAL_HEADER;
? ? }
? ? if(!(ofmt->flags&AVFMT_NOFILE)) {
? ? ? ? ret =avio_open(&ofmtCtx->pb, out_filename,AVIO_FLAG_WRITE);
? ? ? ? if(ret <0) {
? ? ? ? ? ? returnfalse;
? ? ? ? }
? ? }
? ? ret =avformat_write_header(ofmtCtx,NULL);
? ? if(ret <0){
? ? ? ? return false;
? ? }
? ? return true;
}
利用FFmpeg按視頻關鍵幀精準切割。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
推薦閱讀更多精彩內容
- 圖片轉視頻 為什么想將圖片轉視頻? 是這樣的,我打造的任性動圖軟件,在編輯制作GIF動圖方面,已經基本完善。現在想...
- 在上一篇筆記中我們已經完成了使用SDL播放聲音和視頻,聲音播放沒有什么問題,而視頻播放太快,很明顯視頻沒有同步。在...