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".