Gonzalo GarramuñoThank you very much for your help.

I think I'm completely confused ((

I just want to read the incoming video file (it contains video and audio),
then resize the video and save it in the same format (.ts).

My plan:
1. Open the video and select the desired streams (line 123-126)
2. Prepare AVCodecContext (line 207-214)
3. Decode video frame
4. I change the size of the frame (sws_scale ())
5. I encode the frame (line 352)
6. I write the frame to a file (line 372)

line 352 (avcodec_send_frame ()) constantly returns -22

it seems to me that somewhere I am making a fundamental mistake ((



сб, 3 квіт. 2021 о 16:29 Gonzalo Garramuño <[email protected]> пише:

>
> El 3/4/21 a las 06:21, Сергей Икол escribió:
>
> Hello!
>
> I use this example
>
> https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/2_remuxing.c
>
> I want to change this example a little to resize the output video stream
> Is it posible?
> Can I use sws_scale() for this? Or do I need to use some other method for
> this?
>
> I would be glad for any advice!)
>
> Yes it is possible and yes you can use sws_scale for this.  Just make sure
> you are using the right pix_fmt and have the right linesizes in addition to
> the new resolution and all should be fine.
> _______________________________________________
> Libav-user mailing list
> [email protected]
> https://ffmpeg.org/mailman/listinfo/libav-user
>
> To unsubscribe, visit link above, or email
> [email protected] with subject "unsubscribe".
// based on https://ffmpeg.org/doxygen/trunk/remuxing_8c-example.html

#include <iostream>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/timestamp.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
    //    #include <libavutil/dict.h>
}

static void fill_yuv_image(uint8_t *data[4], int linesize[4],
                           int width, int height, int frame_index)
{
    int x, y;
    /* Y */
    for (y = 0; y < height; y++)
        for (x = 0; x < width; x++)
            data[0][y * linesize[0] + x] = x + y + frame_index * 3;
    /* Cb and Cr */
    for (y = 0; y < height / 2; y++)
    {
        for (x = 0; x < width / 2; x++)
        {
            data[1][y * linesize[1] + x] = 128 + y + frame_index * 2;
            data[2][y * linesize[2] + x] = 64 + x + frame_index * 5;
        }
    }
}

int write_frame(AVFormatContext *fmt_ctx, AVCodecContext *c, AVStream *st, AVFrame *frame);

int close(AVFormatContext *input_format_context, AVFormatContext *output_format_context, int *streams_list, int ret);

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;

    std::cout << tag << " pts: " << pkt->pts << " pts_time: " << av_q2d(*time_base) * pkt->pts
              << " dts: " << pkt->dts << " dts_time: " << av_q2d(*time_base) * pkt->dts
              << " duration: " << pkt->duration << " duration_time: " << av_q2d(*time_base) * pkt->duration
              << " stream_index: " << pkt->stream_index
              << std::endl;
}

int main(int argc, char **argv)
{
    AVCodecContext *in_cctx = NULL, *out_cctx = NULL;
    struct SwsContext *resize;

    AVFormatContext *input_format_context = NULL, *output_format_context = NULL;
    AVPacket packet;
    const char *in_filename, *out_filename;
    int ret, i;
    int stream_index = 0;
    int *streams_list = NULL;
    int number_of_streams = 0;
    int fragmented_mp4_options = 0;
    int vStream = -1;
    int aStream = -1;
    int outWidth = 320;
    int outHeight = 240;

    if (argc < 3)
    {
        printf("You need to pass at least two parameters.\n");
        return -1;
    }
    else if (argc == 4)
    {
        fragmented_mp4_options = 1;
    }

    in_filename = argv[1];
    out_filename = argv[2];

    AVDictionary *opts1 = NULL;

    av_dict_set(&opts1, "pixel_format", "rgb24", 0);
    av_dict_set(&opts1, "b", "800k", 0);

    AVDictionaryEntry *e;
    if (e = av_dict_get(opts1, "", NULL, AV_DICT_IGNORE_SUFFIX))
    {
        fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key);
    }

    if ((ret = avformat_open_input(&input_format_context, in_filename, NULL, &opts1)) < 0)
    {
        fprintf(stderr, "Could not open input file '%s'", in_filename);
        close(input_format_context, output_format_context, streams_list, ret);
    }
    if ((ret = avformat_find_stream_info(input_format_context, NULL)) < 0)
    {
        fprintf(stderr, "Failed to retrieve input stream information");
        close(input_format_context, output_format_context, streams_list, ret);
    }

    avformat_alloc_output_context2(&output_format_context, NULL, NULL, out_filename);
    if (!output_format_context)
    {
        fprintf(stderr, "Could not create output context\n");
        ret = AVERROR_UNKNOWN;
        close(input_format_context, output_format_context, streams_list, ret);
    }

    number_of_streams = input_format_context->nb_streams;
    streams_list = (int *)av_mallocz_array(number_of_streams, sizeof(*streams_list));

    if (!streams_list)
    {
        ret = AVERROR(ENOMEM);
        close(input_format_context, output_format_context, streams_list, ret);
    }

    for (i = 0; i < input_format_context->nb_streams; i++)
    {
        AVStream *out_stream;
        AVStream *in_stream = input_format_context->streams[i];
        AVCodecParameters *in_codecpar = in_stream->codecpar;
        // if (i < 7 || i > 8)
        if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
            in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
        {
            streams_list[i] = -1;
            continue;
        }

        if (in_codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            in_cctx = input_format_context->streams[i]->codec;
            vStream = i;
        }
        if (in_codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            aStream = i;
        }

        streams_list[i] = stream_index++;
        out_stream = avformat_new_stream(output_format_context, NULL);
        if (!out_stream)
        {
            fprintf(stderr, "Failed allocating output stream\n");
            ret = AVERROR_UNKNOWN;
            close(input_format_context, output_format_context, streams_list, ret);
        }

        ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
        if (ret < 0)
        {
            fprintf(stderr, "Failed to copy codec parameters\n");
            close(input_format_context, output_format_context, streams_list, ret);
        }
    }
    // https://ffmpeg.org/doxygen/trunk/group__lavf__misc.html#gae2645941f2dc779c307eb6314fd39f10
    av_dump_format(output_format_context, 0, out_filename, 1);

    // unless it's a no file (we'll talk later about that) write to the disk (FLAG_WRITE)
    // but basically it's a way to save the file to a buffer so you can store it
    // wherever you want.
    if (!(output_format_context->oformat->flags & AVFMT_NOFILE))
    {
        ret = avio_open(&output_format_context->pb, out_filename, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            fprintf(stderr, "Could not open output file '%s'", out_filename);
            close(input_format_context, output_format_context, streams_list, ret);
        }
    }
    AVDictionary *opts = NULL;

    if (fragmented_mp4_options)
    {
        // https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE
        av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0);
        // av_dict_set(&opts, "-vf", "scale=320:240 ", 0);
        // av_dict_set(&opts, "video_size", "320x240", 0);
        // av_dict_set(&opts, "pixel_format", "rgb24", 0);
    }
    // https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga18b7b10bb5b94c4842de18166bc677cb
    ret = avformat_write_header(output_format_context, &opts);
    if (ret < 0)
    {
        fprintf(stderr, "Error occurred when opening output file\n");
        close(input_format_context, output_format_context, streams_list, ret);
    }

    int packN = 0;
    int64_t lastTaPts = 0;
    int64_t lastTaDts = 0;
    int64_t lastTvPts = 0;
    int64_t lastTvDts = 0;
    int64_t TvPts = 0;
    int64_t TvDts = 127018;
    int64_t TaPts = 0;
    int64_t TaDts = 127018;
    int64_t Tpts = 0;
    int64_t Tdts = 0;

    AVCodec *codec = avcodec_find_decoder(in_cctx->codec_id);
    avcodec_open2(in_cctx, codec, NULL);
    out_cctx = avcodec_alloc_context3(codec);
    out_cctx->bit_rate = in_cctx->bit_rate;
    out_cctx->width = outWidth;
    out_cctx->height = outHeight;
    out_cctx->time_base = (AVRational){1, 25};
    out_cctx->framerate = (AVRational){25, 1};

    resize = sws_getContext(in_cctx->width, in_cctx->height, AV_PIX_FMT_YUV420P, outWidth, outHeight, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

    while (1)
    {
        AVStream *in_stream, *out_stream;
        ret = av_read_frame(input_format_context, &packet);

        if (ret < 0)
        {
            std::cout << "Read frame error" << std::endl;
            break;
        }

        if (packet.stream_index == vStream)
        {
            AVFrame *frame = av_frame_alloc();

            int response = avcodec_send_packet(in_cctx, &packet);

            if (response < 0)
            {
                std::cout << "Error while sending a packet to the decoder" << std::endl;
                continue;
            }

            while (response >= 0)
            {
                // Return decoded output data (into a frame) from a decoder
                // https://ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga11e6542c4e66d3028668788a1a74217c
                response = avcodec_receive_frame(in_cctx, frame);
                if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
                {
                    break;
                }
                else if (response < 0)
                {
                    std::cout << "Error while receiving a frame from the decoder" << std::endl;
                }

                if (response >= 0)
                {
                    if (frame->format != AV_PIX_FMT_YUV420P)
                    {
                        std::cout << "Warning: the generated file may not be a grayscale image, but could e.g. be just the R component if the video format is RGB" << std::endl;
                    }

                    if (frame != NULL)
                    {
                        // AVFrame *frame1 = av_frame_alloc(); // this is your original frame
                        AVFrame *out_frame = av_frame_alloc();

                        av_frame_copy_props(out_frame, frame);

                        out_frame->format = frame->format;
                        out_frame->width = outWidth;
                        out_frame->height = outHeight;
                        out_frame->channels = frame->channels;
                        out_frame->channel_layout = frame->channel_layout;
                        out_frame->nb_samples = frame->nb_samples;

                        int num_bytes = avpicture_get_size(AV_PIX_FMT_YUV420P, outWidth, outHeight);
                        uint8_t *out_frame_buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));
                        avpicture_fill((AVPicture *)out_frame, out_frame_buffer, AV_PIX_FMT_YUV420P, outWidth, outHeight);
                        // frame1 should be filled by now (eg using avcodec_decode_video)
                        int r = sws_scale(resize, frame->data, frame->linesize, 0, frame->height, out_frame->data, out_frame->linesize);

                        if (r > 0)
                        {
                            write_frame(output_format_context, out_cctx, out_stream, out_frame);
                        }
                    }
                }
            }
        }

        // in_stream = input_format_context->streams[packet.stream_index];
        // if (packet.stream_index >= number_of_streams || streams_list[packet.stream_index] < 0)
        // {
        //     av_packet_unref(&packet);
        //     // std::cout << "stream_index >= number_of_streams" << std::endl;
        //     continue;
        // }
        // packet.stream_index = streams_list[packet.stream_index];
        // out_stream = output_format_context->streams[packet.stream_index];
        // /* copy packet */

        // log_packet(output_format_context, &packet, "in");

        // packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        // packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        // packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
        // // https://ffmpeg.org/doxygen/trunk/structAVPacket.html#ab5793d8195cf4789dfb3913b7a693903
        // packet.pos = -1;

        // log_packet(output_format_context, &packet, "out");

        //https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga37352ed2c63493c38219d935e71db6c1
        // ret = av_interleaved_write_frame(output_format_context, &packet);

        // if (ret < 0)
        // {
        //     fprintf(stderr, "Error muxing packet\n");
        //     av_packet_unref(&packet);
        // }

        // std::cout << "end loop" << std::endl;
    }
    //https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga7f14007e7dc8f481f054b21614dfec13
    av_write_trailer(output_format_context);

    close(input_format_context, output_format_context, streams_list, ret);
}

int close(AVFormatContext *input_format_context, AVFormatContext *output_format_context, int *streams_list, int ret)
{
    std::cout << "close" << std::endl;

    avformat_close_input(&input_format_context);
    /* close output */
    if (output_format_context && !(output_format_context->oformat->flags & AVFMT_NOFILE))
        avio_closep(&output_format_context->pb);
    avformat_free_context(output_format_context);
    av_freep(&streams_list);
    if (ret < 0 && ret != AVERROR_EOF)
    {
        //fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
        return 1;
    }
    return 0;
}

int write_frame(AVFormatContext *fmt_ctx, AVCodecContext *c,
                AVStream *st, AVFrame *frame)
{
    int ret;
    // send the frame to the encoder
    ret = avcodec_send_frame(c, frame); // always returns -22
    if (ret < 0)
    {
        exit(1);
    }
    while (ret >= 0)
    {
        AVPacket pkt = {0};
        ret = avcodec_receive_packet(c, &pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            break;
        else if (ret < 0)
        {
            exit(1);
        }
        /* rescale output packet timestamp values from codec to stream timebase */
        av_packet_rescale_ts(&pkt, c->time_base, st->time_base);
        pkt.stream_index = st->index;
        /* Write the compressed frame to the media file. */
        log_packet(fmt_ctx, &pkt, "whrite");
        ret = av_interleaved_write_frame(fmt_ctx, &pkt);
        av_packet_unref(&pkt);
        if (ret < 0)
        {
            exit(1);
        }
    }
    return ret == AVERROR_EOF ? 1 : 0;
}
_______________________________________________
Libav-user mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Reply via email to