How to cut video with FFmpeg C API

How can I cut video with FFmpeg C API? From 00:10:00 to 00:20:00 for example. What functions I need to use?

I convert video using this function:

int convert(char *file) {
    AVFrame *frame;
    AVPacket inPacket, outPacket;

    if(avio_open(&outFormatContext->pb, file, AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "convert(): cannot open out file\n");
        return 0;
    }

    avformat_write_header(outFormatContext, NULL);
    frame = avcodec_alloc_frame();
    av_init_packet(&inPacket);

    while(av_read_frame(inFormatContext, &inPacket) >= 0) {
        if(inPacket.stream_index == inVideoStreamIndex) {
            avcodec_decode_video2(inCodecContext, frame, &frameFinished, &inPacket);
            if(frameFinished) {
                av_init_packet(&outPacket);
                avcodec_encode_video2(outCodecContext, &outPacket, frame, &outputed);
                if(outputed) {
                    if (av_write_frame(outFormatContext, &outPacket) != 0) {
                        fprintf(stderr, "convert(): error while writing video frame\n");
                        return 0;
                    }
                }
                av_free_packet(&outPacket);
            }
        }
    }

    av_write_trailer(outFormatContext);
    av_free_packet(&inPacket);
    return 1;
}

c api ffmpeg

shareimprove this question

edited Dec 31 '13 at 11:45

meaning-matters

11.9k44494

asked Dec 31 '13 at 11:40

Ilya Zharkov

114210

  • 1

    Please explain what you have already tried. Did you Google the subject? What did not work for you? – Bas van Dijk Dec 31 '13 at 11:57

  • I didn't find any example for C API. May be I need to use function avformat_seek_file which will find start position. But I'm new to FFmpeg and don't know what to do next. – Ilya Zharkov Dec 31 '13 at 12:25

add a comment

2 Answers

activeoldestvotes

7

 

If you just wanna cut the video, you don't need to reencode the video if you want. So I am supposing you wanna cut and reencode for some reason. So, based on your code:

Observe you must to have access to the video AVStream* structure... I named it as inVideoStream.

int convert_and_cut(char *file, float starttime, float endtime) {
    AVFrame *frame;
    AVPacket inPacket, outPacket;

    if(avio_open(&outFormatContext->pb, file, AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "convert(): cannot open out file\n");
        return 0;
    }

    // seek to the start time you wish.
    // BEGIN
    AVRational default_timebase;
    default_timebase.num = 1;
    default_timebase.den = AV_TIME_BASE;

    // suppose you have access to the "inVideoStream" of course
    int64_t starttime_int64 = av_rescale_q((int64_t)( starttime * AV_TIME_BASE ), default_timebase, inVideoStream->time_base);
    int64_t endtime_int64 = av_rescale_q((int64_t)( endtime * AV_TIME_BASE ), default_timebase, inVideoStream->time_base);

    if(avformat_seek_file(inFormatContext, inVideoStreamIndex, INT64_MIN, starttime_int64, INT64_MAX, 0) < 0) {
        // error... do something...
        return 0; // usually 0 is used for success in C, but I am following your code.
    }

    avcodec_flush_buffers( inVideoStream->codec );
    // END

    avformat_write_header(outFormatContext, NULL);
    frame = avcodec_alloc_frame();
    av_init_packet(&inPacket);

    // you used avformat_seek_file() to seek CLOSE to the point you want... in order to give precision to your seek,
    // just go on reading the packets and checking the packets PTS (presentation timestamp) 
    while(av_read_frame(inFormatContext, &inPacket) >= 0) {
        if(inPacket.stream_index == inVideoStreamIndex) {
            avcodec_decode_video2(inCodecContext, frame, &frameFinished, &inPacket);
            // this line guarantees you are getting what you really want.
            if(frameFinished && frame->pkt_pts >= starttime_int64 && frame->pkt_pts <= endtime_int64) {
                av_init_packet(&outPacket);
                avcodec_encode_video2(outCodecContext, &outPacket, frame, &outputed);
                if(outputed) {
                    if (av_write_frame(outFormatContext, &outPacket) != 0) {
                        fprintf(stderr, "convert(): error while writing video frame\n");
                        return 0;
                    }
                }
                av_free_packet(&outPacket);
            }

            // exit the loop if you got the frames you want.
            if(frame->pkt_pts > endtime_int64) {
                break;
            }
        }
    }

    av_write_trailer(outFormatContext);
    av_free_packet(&inPacket);
    return 1;
}

shareimprove this answer

answered Dec 31 '13 at 17:25

Wagner Patriota

4,0511940

  • 1

    It's a really good answer. Thank you for the help. – Ilya Zharkov Jan 1 '14 at 15:02

  • Could you please explain frameFinished and outputed variables? – AnujAroshA Jul 16 '15 at 12:59

  • when you decode a single packet, you still don't have information enough to have a frame [depending on the type of codec, some of them you do], when you decode a GROUP of packets that represents a frame, then you have a picture! that's why frameFinished will let you know you decoded enough to have a frame. – Wagner Patriota Jul 16 '15 at 17:15

  • a similar logic happens to outputed. depending on the codec you have a packet for every frame, but some of them you don't... so let's say that avcodec_encode_video2 accumulates information until it's ready to output a packet. then you save this packet. – Wagner Patriota Jul 16 '15 at 17:19

add a comment

6

 

As Wagner Patriota says, "if you just wanna cut the video, you don't need to reencode the video if you want". Here is the code based on ffmpeg remuxing.c example that you don't need to reencode the video.

#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>

static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
{
    AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;

    printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
           tag,
           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
           av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
           pkt->stream_index);
}

int cut_video(double from_seconds, double end_seconds, const char* in_filename, const char* out_filename) {
    AVOutputFormat *ofmt = NULL;
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    int ret, i;

    av_register_all();

    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
        fprintf(stderr, "Could not open input file '%s'", in_filename);
        goto end;
    }

    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
        fprintf(stderr, "Failed to retrieve input stream information");
        goto end;
    }

    av_dump_format(ifmt_ctx, 0, in_filename, 0);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值