[Libav-user] Grabbing packets from avfoundation with reencoding and muxing
Valeriy Shtoma
shtomavaleriy at gmail.com
Thu Dec 14 16:49:57 EET 2017
Hi to all guys,
I don’t understand what I do wrong? I saw all examples,
saw headers with API description… Where is my fault?
To begin with this, my code:
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>
int open_input_device(AVFormatContext **ifmt_ctx,
const char* device_name,
AVInputFormat **ifmt,
AVDictionary *iopt) {
// Open input video file
if (avformat_open_input(ifmt_ctx, device_name, *ifmt, &iopt) != 0) {
printf("%s\n", "Couldn't open input file");
return -1;
}
// Retrieve stream information
if (avformat_find_stream_info(*ifmt_ctx, NULL) < 0) {
printf("%s\n", "Couldn't find stream information");
return -1;
}
// Dump information about input media onto standard error
av_dump_format(*ifmt_ctx, 0, device_name, 0);
return 0;
}
int main(void) {
/* Inputs */
AVFormatContext *ifmt_ctx = NULL;
AVInputFormat *ifmt = NULL;
AVDictionary *iopt = NULL;
AVDictionary *libx264opt = NULL;
AVCodec *ivcdc = NULL;
AVCodecContext *ivcdc_ctx = NULL;
AVCodec *iacdc = NULL;
AVCodecContext *iacdc_ctx = NULL;
AVPacket ipkt;
/* Outputs */
const char *rtmpUrl = "test.flv";
AVFormatContext *ofmt_ctx;
AVOutputFormat *ofmt;
AVCodec *ovcdc = NULL;
AVCodecContext *ovcdc_ctx = NULL;
AVCodec *oacdc = NULL;
AVCodecContext *oacdc_ctx = NULL;
AVPacket opkt;
/* Utils */
int i, ret = -1, vindex = -1, aindex = -1;
av_register_all();
avformat_network_init();
avdevice_register_all();
avcodec_register_all();
//Grab AVFoundation settings
ifmt = av_find_input_format("avfoundation");
av_dict_set(&iopt, "video_size", "1280x720", 0);
av_dict_set(&iopt, "probesize", "100M", 0);
av_dict_set(&iopt, "analyzeduration", "100M", 0);
open_input_device(&ifmt_ctx, "0:1", &ifmt, iopt);
ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", rtmpUrl);
if (!ofmt_ctx || ret < 0) {
printf("%s\n", "Can't allocate the output media context");
return -1;
}
ofmt_ctx->probesize = 100000000;
ofmt_ctx->max_analyze_duration = 100000000;
ofmt = ofmt_ctx->oformat;
ofmt->video_codec = AV_CODEC_ID_H264;
ofmt->audio_codec = AV_CODEC_ID_MP3;
ofmt->flags |= AVFMT_GLOBALHEADER;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
if (ifmt_ctx->streams[i]->codecpar->codec_type ==
AVMEDIA_TYPE_VIDEO) {
vindex = i;
ivcdc = avcodec_find_decoder(ifmt_ctx->streams[i]->
codecpar->codec_id);
if (!ivcdc) {
printf("%s\n", "Failed to find decoder for input video stream");
return -1;
}
ivcdc_ctx = avcodec_alloc_context3(ivcdc);
if (!ivcdc_ctx) {
printf("%s\n", "Failed to allocate the decoder
context for input video stream");
return -1;
}
ret = avcodec_parameters_to_context(ivcdc_ctx, ifmt_ctx->
streams[i]->codecpar);
if (ret < 0) {
printf("%s\n", "Failed to copy decoder parameters
to video input decoder context");
return -1;
}
/* Open decoder */
ret = avcodec_open2(ivcdc_ctx, ivcdc, NULL);
if (ret < 0) {
printf("%s\n", "Failed to open decoder for video input stream");
return -1;
}
// Output
ovcdc = avcodec_find_encoder(ofmt->video_codec);
if (!ovcdc) {
printf("%s\n", "Failed to find encoder for output video stream");
return -1;
}
ovcdc_ctx = avcodec_alloc_context3(ovcdc);
if (!ovcdc_ctx) {
printf("%s\n", "Failed to allocate the encoder context
for output video stream");
return -1;
}
ovcdc_ctx->width = 1280;
ovcdc_ctx->height = 720;
ovcdc_ctx->coded_width = 1280;
ovcdc_ctx->coded_height = 720;
ovcdc_ctx->bit_rate = 2000000;
ovcdc_ctx->gop_size = 60;
ovcdc_ctx->pix_fmt = AV_PIX_FMT_YUV422P;
ovcdc_ctx->time_base = (AVRational){1, 30};
ovcdc_ctx->framerate = (AVRational){30, 1};
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
ovcdc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
AVStream *ost = avformat_new_stream(ofmt_ctx, ovcdc);
if (!ost) {
printf("%s\n", "Failed add new video stream to output");
return -1;
}
ost->id = ofmt_ctx->nb_streams - 1;
ret = avcodec_parameters_from_context(ost->codecpar, ovcdc_ctx);
if (ret < 0) {
printf("%s\n", "Failed to copy video encoder
parameters to output video encoder context");
return -1;
}
ost->avg_frame_rate = ovcdc_ctx->framerate;
ost->r_frame_rate = ovcdc_ctx->framerate;
ost->time_base = ovcdc_ctx->time_base;
/* Open encoder */
av_dict_set(&libx264opt, "profile:v", "high422", 0);
av_dict_set(&libx264opt, "level", "41", 0);
av_dict_set(&libx264opt, "preset", "ultrafast", 0);
av_dict_set(&libx264opt, "tune", "zerolatency", 0);
av_dict_set(&libx264opt, "crf", "23", 0);
av_dict_set(&libx264opt, "g", "60", 0);
av_dict_set(&libx264opt, "maxrate", "2500k", 0);
av_dict_set(&libx264opt, "bufsize", "2500k", 0);
ret = avcodec_open2(ovcdc_ctx, ovcdc, &libx264opt);
if (ret < 0) {
printf("%s\n", "Failed to open encoder for video output stream");
return -1;
}
} else if (ifmt_ctx->streams[i]->codecpar->codec_type
== AVMEDIA_TYPE_AUDIO) {
aindex = i;
iacdc = avcodec_find_decoder(ifmt_ctx->streams[i]->
codecpar->codec_id);
if (!iacdc) {
printf("%s\n", "Failed to find decoder for input audio stream");
return -1;
}
iacdc_ctx = avcodec_alloc_context3(iacdc);
if (!iacdc_ctx) {
printf("%s\n", "Failed to allocate the decoder
context for input audio stream");
return -1;
}
ret = avcodec_parameters_to_context(iacdc_ctx, ifmt_ctx->
streams[i]->codecpar);
if (ret < 0) {
printf("%s\n", "Failed to copy decoder parameters
to audio input decoder context");
return -1;
}
/* Open decoder */
ret = avcodec_open2(iacdc_ctx, iacdc, NULL);
if (ret < 0) {
printf("%s\n", "Failed to open decoder for audio input stream");
return -1;
}
// Output
oacdc = avcodec_find_encoder(ofmt->audio_codec);
if (!oacdc) {
printf("%s\n", "Failed to find encoder for output audio stream");
return -1;
}
oacdc_ctx = avcodec_alloc_context3(oacdc);
if (!oacdc_ctx) {
printf("%s\n", "Failed to allocate the encoder context for
output audio stream");
return -1;
}
oacdc_ctx->sample_fmt = oacdc->sample_fmts ?
oacdc->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
oacdc_ctx->bit_rate = 192000;
if (oacdc->supported_samplerates) {
oacdc_ctx->sample_rate = oacdc->supported_samplerates[0];
for (int j = 0; oacdc->supported_samplerates[j]; j++) {
if (oacdc->supported_samplerates[j] == 44100)
oacdc_ctx->sample_rate = 44100;
}
}
oacdc_ctx->channels = av_get_channel_layout_nb_channels(iacdc_ctx->
channel_layout);
if (oacdc->channel_layouts) {
oacdc_ctx->channel_layout = oacdc->channel_layouts[0];
for (int j = 0; oacdc->channel_layouts[j]; j++) {
if (oacdc->channel_layouts[j] == AV_CH_LAYOUT_STEREO)
oacdc_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
}
}
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
oacdc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
AVStream *ost = avformat_new_stream(ofmt_ctx, oacdc);
if (!ost) {
printf("%s\n", "Failed add new audio stream to output");
return -1;
}
ost->id = ofmt_ctx->nb_streams - 1;
ret = avcodec_parameters_from_context(ost->codecpar, oacdc_ctx);
if (ret < 0) {
printf("%s\n", "Failed to copy audio encoder parameters to
output audio encoder context");
return -1;
}
ost->time_base = (AVRational){1, oacdc_ctx->sample_rate};
/* Open encoder */
ret = avcodec_open2(oacdc_ctx, oacdc, NULL);
if (ret < 0) {
printf("%s\n", "Failed to open encoder for audio output stream");
return -1;
}
}
}
if (vindex == -1 || aindex == -1) {
printf("%s\n", "Didn't find a video or audio input stream");
return -1;
}
/* open the output file, if needed */
if (!(ofmt_ctx->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, rtmpUrl, AVIO_FLAG_WRITE);
if (ret < 0) {
printf("Could not open '%s': %s\n", rtmpUrl, av_err2str(ret));
return -1;
}
}
/* Write the stream header, if any. */
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
printf("Error occurred when opening output file: %s\n", av_err2str(ret));
return -1;
}
// Dump information about output media onto standard error
av_dump_format(ofmt_ctx, 0, rtmpUrl, 1);
// Init frames for streaming loop
AVFrame *ivframe = av_frame_alloc();
AVFrame *ovframe_yuv422p = av_frame_alloc();
ovframe_yuv422p->width = ovcdc_ctx->width;
ovframe_yuv422p->height = ovcdc_ctx->height;
ovframe_yuv422p->format = ovcdc_ctx->pix_fmt;
int numBytes;
numBytes = av_image_get_buffer_size(ovframe_yuv422p->format,
ovframe_yuv422p->width, ovframe_yuv422p->height, 32);
if (numBytes < 0) {
printf("%s\n", "Didn't count number of bytes for buffer
in process of convertation to yuv422p");
return -1;
}
uint8_t *buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
ret = av_image_fill_arrays(ovframe_yuv422p->data, ovframe_yuv422p->
linesize, buffer, ovframe_yuv422p->format,
ovframe_yuv422p->width, ovframe_yuv422p->height, 32);
if (ret < 0) {
printf("%s\n", "Error occured in av_image_fill_arrays()");
return -1;
}
struct SwsContext *sws_ctx = sws_getContext(ivcdc_ctx->width,
ivcdc_ctx->height, ivcdc_ctx->pix_fmt,
ovframe_yuv422p->width,
ovframe_yuv422p->height, ovframe_yuv422p->format,
SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx) {
printf("%s\n", "Error occured in sws_getContext()");
return -1;
}
AVFrame *iaframe = av_frame_alloc();
AVFrame *oaframe = av_frame_alloc();
oaframe->format = oacdc_ctx->sample_fmt;
oaframe->channel_layout = oacdc_ctx->channel_layout;
oaframe->sample_rate = oacdc_ctx->sample_rate;
if (oacdc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) {
oaframe->nb_samples = 10000;
} else {
oaframe->nb_samples = oacdc_ctx->frame_size;
}
if (oaframe->nb_samples) {
ret = av_frame_get_buffer(oaframe, 0);
if (ret < 0) {
printf("%s\n", "Error allocating an audio buffer");
return -1;
}
}
struct SwrContext *swr_ctx = swr_alloc();
if (!swr_ctx) {
printf("%s\n", "Could not allocate resampler context");
return -1;
}
/* set options */
av_opt_set_int(swr_ctx, "in_channel_count", iacdc_ctx->channels, 0);
av_opt_set_int(swr_ctx, "in_sample_rate", iacdc_ctx->sample_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", iacdc_ctx->sample_fmt, 0);
av_opt_set_int(swr_ctx, "out_channel_count", oacdc_ctx->channels, 0);
av_opt_set_int(swr_ctx, "out_sample_rate", oacdc_ctx->sample_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", oacdc_ctx->sample_fmt, 0);
/* initialize the resampling context */
if ((ret = swr_init(swr_ctx)) < 0) {
printf("%s\n", "Failed to initialize the resampling context");
return -1;
}
while (av_read_frame(ifmt_ctx, &ipkt) >= 0) {
if (ipkt.stream_index == vindex) {
ret = avcodec_send_packet(ivcdc_ctx, &ipkt);
if (ret != 0) {
printf("%s\n", "Error on send packet to decoder");
printf("%s\n", av_err2str(ret));
}
ret = avcodec_receive_frame(ivcdc_ctx, ivframe);
if (ret != 0) {
printf("%s\n", "Error on recieve frame from decoder");
printf("%s\n", av_err2str(ret));
}
ovframe_yuv422p->pict_type = ivframe->pict_type;
ovframe_yuv422p->key_frame = ivframe->key_frame;
ovframe_yuv422p->pts = ivframe->pts;
ovframe_yuv422p->pkt_dts = ivframe->pkt_dts;
ovframe_yuv422p->pts = av_rescale_q(ovframe_yuv422p->
pts, ifmt_ctx->streams[vindex]->time_base,
ofmt_ctx->streams[vindex]->time_base);
// change to yuv422p
sws_scale(sws_ctx, (uint8_t const * const *)ivframe->data,
ivframe->linesize, 0, ivcdc_ctx->height,
ovframe_yuv422p->data, ovframe_yuv422p->linesize);
// encode to libx264
ret = avcodec_send_frame(ovcdc_ctx, ovframe_yuv422p);
if (ret != 0) {
printf("%s\n", "Error on send frame to encoder");
printf("%s\n", av_err2str(ret));
}
do {
ret = avcodec_receive_packet(ovcdc_ctx, &opkt);
if (ret < 0) {
if (ret != AVERROR(EAGAIN)) {
printf("%s\n", "Error on recieve packet from encoder");
printf("%s\n", av_err2str(ret));
}
break;
}
opkt.stream_index = ipkt.stream_index;
av_packet_rescale_ts(&opkt, ifmt_ctx->streams[vindex]->time_base,
ofmt_ctx->streams[vindex]->time_base);
ret = av_interleaved_write_frame(ofmt_ctx, &opkt);
if (ret < 0) {
printf("%s\n", "Error muxing video packet");
break;
}
} while (ret >= 0);
} else if (ipkt.stream_index == aindex) {
ret = avcodec_send_packet(iacdc_ctx, &ipkt);
if (ret != 0) {
printf("%s\n", "Error on send packet to decoder(audio)");
printf("%s\n", av_err2str(ret));
}
ret = avcodec_receive_frame(iacdc_ctx, iaframe);
if (ret != 0) {
printf("%s\n", "Error on recieve frame from decoder(audio)");
printf("%s\n", av_err2str(ret));
}
/* convert to destination format */
ret = swr_convert(swr_ctx, oaframe->data, oaframe->nb_samples,
(const uint8_t **)iaframe->data,
iaframe->nb_samples);
if (ret < 0) {
printf("%s\n", "Error while converting audio frame");
break;
}
oaframe->pts = iaframe->pts;
oaframe->pkt_dts = iaframe->pkt_dts;
oaframe->pts = av_rescale_q(oaframe->pts,
ifmt_ctx->streams[aindex]->time_base,
ofmt_ctx->streams[aindex]->time_base);
ret = avcodec_send_frame(oacdc_ctx, oaframe);
if (ret != 0) {
printf("%s\n", "Error on send frame to encoder");
printf("%s\n", av_err2str(ret));
}
do {
ret = avcodec_receive_packet(oacdc_ctx, &opkt);
if (ret < 0) {
if (ret != AVERROR(EAGAIN)) {
printf("%s\n", "Error on recieve packet from encoder");
printf("%s\n", av_err2str(ret));
}
break;
}
opkt.stream_index = ipkt.stream_index;
av_packet_rescale_ts(&opkt, ifmt_ctx->streams[aindex]->time_base, ofmt_ctx->streams[aindex]->time_base);
ret = av_interleaved_write_frame(ofmt_ctx, &opkt);
if (ret < 0) {
printf("%s\n", "Error muxing audio packet");
break;
}
} while (ret >= 0);
}
av_packet_unref(&ipkt);
}
…
free resources...
I don’t understand why my output file don’t have a keyframe and
video codec info, what’s I do wrong?
So sorry if something is wrong, it’s my first letter to community and
thanks at all.
Kind Regards,
Valeriy V Shtoma
More information about the Libav-user
mailing list