I'm still learning Cin, so if this filter is already in place, then I
apologize.

FFMpeg has a nice audio "filter" called "atempo".

https://ffmpeg.org/ffmpeg-filters.html#atempo

This filter is already in other projects, such as Kdenlive and Shotcut.

What it does is, you can speed up audio, and will adjust the pitch so that
the audio sounds more normal, but faster.

It does not sound like "Alvin and the Chipmunks" :)

This behavior can be seen when you watch a YT video, click the gear icon,
and select a speed greater or less than 1.

I'm attaching the FFMpeg sample code that I had modified/played with years
ago when I was learning it.

I 'tweaked' it today, so it will compile in Ubuntu 21.04 using a c++
compiler.  I used Qt.  There's depreciation warnings and this certainly
isn't production code.  But it should help others to grasp the concepts to
implement it.

My Qt pro file has this:

TEMPLATE = app

CONFIG += console c++11

CONFIG -= app_bundle

CONFIG -= qt


SOURCES += main.cpp

LIBS += -lavcodec -lavformat -lavutil -lswresample -lasound -lavfilter -lasound


I put an Option 1 and Option 2 in the main.cpp file.


Option 1 simple writes your infile - no modifications to out.raw.

Option 2 applies the atempo filter.


So comment and rebuild accordingly.  It should only take 2 seconds or
so to compile.


I'm hoping, that perhaps someday, I can simply drop an effect onto my
timeline so that I can

speed up video/audio in one go and have nicer sounding audio for my needs.


Thank you in advance for your consideration.
// license, same as whatever FFmpeg is - gorge

// As written this file will output a wav compliant raw wav file

// simply play the output file with ffplay -f s16le -ar 44100 -ac 2 out.raw

// note this file does not use fmt_ctx=avformat_alloc_context();  or similar
// perhaps it's init'd in c when its declared?? but for c++ style with
// headers it was definitely needed, typically after avfilter_register_all()

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

extern "C"
{
    #ifndef __STDC_CONSTANT_MACROS
    #  define __STDC_CONSTANT_MACROS
    #endif
    #include <libavcodec/avcodec.h>
    #include <libavfilter/avfilter.h>
//    #include <libavfilter/avfiltergraph.h> // old ffmpeg
    #include <libavfilter/avfilter.h>  // newer ffmpeg
    #include <libavfilter/buffersink.h>
    #include <libavfilter/buffersrc.h>
    #include <libavformat/avformat.h>
    #include <libavformat/avio.h>
    #include <libavutil/attributes.h>
    #include <libavutil/avutil.h>
    #include <libavutil/channel_layout.h>
    #include <libavutil/common.h>
    #include <libavutil/file.h>
    #include <libavutil/imgutils.h>
    #include <libavutil/mathematics.h>
    #include <libavutil/mathematics.h>
    #include <libavutil/opt.h>
    #include <libavutil/opt.h>
    #include <libavutil/samplefmt.h>
    #include <libavutil/timestamp.h>
    #include <libswresample/swresample.h>
    #include <libswscale/swscale.h>
    #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
}
// Example:  DBG("Unsupported format");
#define DBG(x) std::cout<<x<<std::endl

// other nice filters:
// can use: atempo=1.7, extrasereo, earwax,stereotools (karaoke stereotools=mlev=0.015625)

// Option 1: for cingg
// this would be for a raw file at same speed:
//static const char *filter_descr = "aresample=44100,aformat=sample_fmts=s16:channel_layouts=stereo";

// Option 2: for cingg
// this would be for a raw file that is "sped up"
static const char *filter_descr = "atempo=1.7,aresample=44100,aformat=sample_fmts=s16:channel_layouts=stereo";

static AVFormatContext *fmt_ctx;
static AVCodecContext *dec_ctx;
static AVFilterContext *buffersink_ctx;
static AVFilterContext *buffersrc_ctx;
static AVFilterGraph *filter_graph;
static int audio_stream_index = -1;

static int open_input_file(const char *filename)
{
    AVCodec *dec;

    avformat_open_input(&fmt_ctx, filename, NULL, NULL);
    avformat_find_stream_info(fmt_ctx, NULL);
    // Dump to stdout info about the source file:
    av_dump_format(fmt_ctx,0,filename,false);
    /* select the audio stream */
    audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);
    dec_ctx = fmt_ctx->streams[audio_stream_index]->codec;
    av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);
    /* init the audio decoder */
    avcodec_open2(dec_ctx, dec, NULL);

    return 0;
}

static int init_filters(const char *filters_descr)
{
    char args[512];
    int ret = 0;
    // older ffmpegs, we didn't require const next two
    const AVFilter *abuffersrc  = avfilter_get_by_name("abuffer");
    const AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs  = avfilter_inout_alloc();
    static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16 }; // we deleted , -1 at end
    static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_STEREO, -1 };
    static const int out_sample_rates[] = { 44100, -1 };
    const AVFilterLink *outlink;
    AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;

    filter_graph = avfilter_graph_alloc();

    /* buffer audio source: the decoded frames from the decoder will be inserted here. */
    if (!dec_ctx->channel_layout)
        dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
    snprintf(args, sizeof(args),
            "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%" PRIx64,
             time_base.num, time_base.den, dec_ctx->sample_rate,
             av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
    avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
                                       args, NULL, filter_graph);

    /* buffer audio sink: to terminate the filter chain. */

    avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
                                       NULL, NULL, filter_graph);

    av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
                              AV_OPT_SEARCH_CHILDREN);

    av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
                              AV_OPT_SEARCH_CHILDREN);

    av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
                              AV_OPT_SEARCH_CHILDREN);


    /*
     * Set the endpoints for the filter graph. The filter_graph will
     * be linked to the graph described by filters_descr.
     */

    /*
     * The buffer source output must be connected to the input pad of
     * the first filter described by filters_descr; since the first
     * filter input label is not specified, it is set to "in" by
     * default.
     */
    outputs->name       = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx    = 0;
    outputs->next       = NULL;

    /*
     * The buffer sink input must be connected to the output pad of
     * the last filter described by filters_descr; since the last
     * filter output label is not specified, it is set to "out" by
     * default.
     */
    inputs->name       = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx    = 0;
    inputs->next       = NULL;

    avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL);
    ret = avfilter_graph_config(filter_graph, NULL);


    /* Print summary of the sink buffer
     * Note: args buffer is reused to store channel layout string */
    outlink = buffersink_ctx->inputs[0];
    av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout);

//end:
//    avfilter_inout_free(&inputs);
//    avfilter_inout_free(&outputs);
    return ret;
}

int main(int argc, char *argv[])
{
    char const * filepath = "/home/gorge/infile.mp3";
    char const * outfilepath = "/home/gorge/out.raw";
    // for filewriting to a file, play it with ffplay -f s16le -ar 44100 -ac 2 out.raw
    FILE * pFile = NULL;
    pFile=fopen(outfilepath, "wb");

    int ret;
    AVPacket packet0, packet;
    AVFrame *frame = av_frame_alloc();
    AVFrame *filt_frame = av_frame_alloc();
    int got_frame;

    if (!frame || !filt_frame) {
        perror("Could not allocate frame");
        exit(1);
    }

    av_register_all();
    avfilter_register_all();

    if ((ret = open_input_file(filepath)) < 0){
        goto end;
    }
    if ((ret = init_filters(filter_descr)) < 0){
        goto end;
    }

    /* read all packets */
    packet0.data = NULL;
    packet.data = NULL;
    while (1) {
        if (!packet0.data) {
            if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
                break;
            packet0 = packet;
        }

        if (packet.stream_index == audio_stream_index) {
            got_frame = 0;
            ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, &packet);
            if (ret < 0) {
                av_log(NULL, AV_LOG_ERROR, "Error decoding audio\n");
                continue;
            }
            packet.size -= ret;
            packet.data += ret;

            if (got_frame) {
                /* push the audio data from decoded frame into the filtergraph */
                if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, 0) < 0) {
                    av_log(NULL, AV_LOG_ERROR, "Error while feeding the audio filtergraph\n");
                    break;
                }

                /* pull filtered audio from the filtergraph */
                while (1) {
                    ret = av_buffersink_get_frame(buffersink_ctx, filt_frame);
                    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
                        break;
                    }
                    if (ret < 0){
                       goto end;
                    }

                    // Play the frame
                    const int n = filt_frame->nb_samples * 4; // libao & pulse requires * 4 at end, alsa gets nothing
                    const uint16_t *p     = (uint16_t*)filt_frame->data[0];


                    fwrite(p,1,n,pFile);

                    av_frame_unref(filt_frame);
                }
            }

            if (packet.size <= 0)
                av_packet_unref(&packet0);
        } else {
            /* discard non-wanted packets */
            av_packet_unref(&packet0);
        }
    }
end:
    avfilter_graph_free(&filter_graph);
    avcodec_close(dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&frame);
    av_frame_free(&filt_frame);

    exit(0);
}



-- 
Cin mailing list
[email protected]
https://lists.cinelerra-gg.org/mailman/listinfo/cin

Reply via email to