How to cut video with FFmpeg C API

Viewed 6713

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;
}
3 Answers

In addition, as ustin says, the code based on ffmpeg remuxing.c example.

  1. add out_stream->time_base = in_stream->time_base; before out_stream->codec->codec_tag = 0;

  2. add int64_t *start_from = NULL; after int stream_mapping_size = 0;

  3. add start_from = av_mallocz_array(stream_mapping_size, sizeof(*start_from)); after stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));

  4. add start_from[stream_mapping[i]] = INT16_MIN; after stream_mapping[i] = stream_index++;

  5. add

if (start_from[pkt.stream_index] == INT16_MIN) {
    int64_t dts = pkt.dts;
    int64_t pts = pkt.pts;
    int64_t min_ts = dts > pts ? pts : dts;
    start_from[pkt.stream_index] = min_ts < 0 ? 0 : min_ts;
}

After

if (pkt.stream_index >= stream_mapping_size ||
   stream_mapping[pkt.stream_index] < 0) {
        av_packet_unref(&pkt);
        continue;
}
  1. change justin code, about pts/dst set value to this:
pkt.pts = av_rescale_q_rnd(pkt.pts - start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

pkt.dts = av_rescale_q_rnd(pkt.dts - start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
  1. add free(start_from); before end:

Tips: start/end timestamp like justin says

Related