
Recherche avancée
Médias (1)
-
The Great Big Beautiful Tomorrow
28 octobre 2011, par
Mis à jour : Octobre 2011
Langue : English
Type : Texte
Autres articles (28)
-
Publier sur MédiaSpip
13 juin 2013Puis-je poster des contenus à partir d’une tablette Ipad ?
Oui, si votre Médiaspip installé est à la version 0.2 ou supérieure. Contacter au besoin l’administrateur de votre MédiaSpip pour le savoir -
Les tâches Cron régulières de la ferme
1er décembre 2010, parLa gestion de la ferme passe par l’exécution à intervalle régulier de plusieurs tâches répétitives dites Cron.
Le super Cron (gestion_mutu_super_cron)
Cette tâche, planifiée chaque minute, a pour simple effet d’appeler le Cron de l’ensemble des instances de la mutualisation régulièrement. Couplée avec un Cron système sur le site central de la mutualisation, cela permet de simplement générer des visites régulières sur les différents sites et éviter que les tâches des sites peu visités soient trop (...) -
Déploiements possibles
31 janvier 2010, parDeux types de déploiements sont envisageable dépendant de deux aspects : La méthode d’installation envisagée (en standalone ou en ferme) ; Le nombre d’encodages journaliers et la fréquentation envisagés ;
L’encodage de vidéos est un processus lourd consommant énormément de ressources système (CPU et RAM), il est nécessaire de prendre tout cela en considération. Ce système n’est donc possible que sur un ou plusieurs serveurs dédiés.
Version mono serveur
La version mono serveur consiste à n’utiliser qu’une (...)
Sur d’autres sites (6087)
-
Encoding of raw frames (D3D11Texture2D) to an rtsp stream using libav*
16 juillet 2021, par uzerI have managed to create a rtsp stream using libav* and directX texture (which I am obtaining from GDI API using Bitblit method). Here's my approach for creating live rtsp stream :


- 

-
Create output context and stream (skipping the checks here)


- 

- avformat_alloc_output_context2(&ofmt_ctx, NULL, "rtsp", rtsp_url) ; //RTSP
- vid_codec = avcodec_find_encoder(ofmt_ctx->oformat->video_codec) ;
- vid_stream = avformat_new_stream(ofmt_ctx,vid_codec) ;
- vid_codec_ctx = avcodec_alloc_context3(vid_codec) ;










-
Set codec params


codec_ctx->codec_tag = 0;
codec_ctx->codec_id = ofmt_ctx->oformat->video_codec;
//codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
codec_ctx->width = width; codec_ctx->height = height;
codec_ctx->gop_size = 12;
 //codec_ctx->gop_size = 40;
 //codec_ctx->max_b_frames = 3;
codec_ctx->pix_fmt = target_pix_fmt; // AV_PIX_FMT_YUV420P
codec_ctx->framerate = { stream_fps, 1 };
codec_ctx->time_base = { 1, stream_fps};
if (fctx->oformat->flags & AVFMT_GLOBALHEADER)
 {
 codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 }



-
Initialize video stream


if (avcodec_parameters_from_context(stream->codecpar, codec_ctx) < 0)
{
 Debug::Error("Could not initialize stream codec parameters!");
 return false;
}

AVDictionary* codec_options = nullptr;
if (codec->id == AV_CODEC_ID_H264) {
 av_dict_set(&codec_options, "profile", "high", 0);
 av_dict_set(&codec_options, "preset", "fast", 0);
 av_dict_set(&codec_options, "tune", "zerolatency", 0);
}
// open video encoder
int ret = avcodec_open2(codec_ctx, codec, &codec_options);
if (ret<0) {
 Debug::Error("Could not open video encoder: ", avcodec_get_name(codec->id), " error ret: ", AVERROR(ret));
 return false;
}

stream->codecpar->extradata = codec_ctx->extradata;
stream->codecpar->extradata_size = codec_ctx->extradata_size;



-
Start streaming


// Create new frame and allocate buffer
AVFrame* AllocateFrameBuffer(AVCodecContext* codec_ctx, double width, double height)
{
 AVFrame* frame = av_frame_alloc();
 std::vector framebuf(av_image_get_buffer_size(codec_ctx->pix_fmt, width, height, 1));
 av_image_fill_arrays(frame->data, frame->linesize, framebuf.data(), codec_ctx->pix_fmt, width, height, 1);
 frame->width = width;
 frame->height = height;
 frame->format = static_cast<int>(codec_ctx->pix_fmt);
 //Debug::Log("framebuf size: ", framebuf.size(), " frame format: ", frame->format);
 return frame;
}

void RtspStream(AVFormatContext* ofmt_ctx, AVStream* vid_stream, AVCodecContext* vid_codec_ctx, char* rtsp_url)
{
 printf("Output stream info:\n");
 av_dump_format(ofmt_ctx, 0, rtsp_url, 1);

 const int width = WindowManager::Get().GetWindow(RtspStreaming::WindowId())->GetTextureWidth();
 const int height = WindowManager::Get().GetWindow(RtspStreaming::WindowId())->GetTextureHeight();

 //DirectX BGRA to h264 YUV420p
 SwsContext* conversion_ctx = sws_getContext(width, height, src_pix_fmt,
 vid_stream->codecpar->width, vid_stream->codecpar->height, target_pix_fmt, 
 SWS_BICUBIC | SWS_BITEXACT, nullptr, nullptr, nullptr);
if (!conversion_ctx)
{
 Debug::Error("Could not initialize sample scaler!");
 return;
}

 AVFrame* frame = AllocateFrameBuffer(vid_codec_ctx,vid_codec_ctx->width,vid_codec_ctx->height);
 if (!frame) {
 Debug::Error("Could not allocate video frame\n");
 return;
 }


 if (avformat_write_header(ofmt_ctx, NULL) < 0) {
 Debug::Error("Error occurred when writing header");
 return;
 }
 if (av_frame_get_buffer(frame, 0) < 0) {
 Debug::Error("Could not allocate the video frame data\n");
 return;
 }

 int frame_cnt = 0;
 //av start time in microseconds
 int64_t start_time_av = av_gettime();
 AVRational time_base = vid_stream->time_base;
 AVRational time_base_q = { 1, AV_TIME_BASE };

 // frame pixel data info
 int data_size = width * height * 4;
 uint8_t* data = new uint8_t[data_size];
// AVPacket* pkt = av_packet_alloc();

 while (RtspStreaming::IsStreaming())
 {
 /* make sure the frame data is writable */
 if (av_frame_make_writable(frame) < 0)
 {
 Debug::Error("Can't make frame writable");
 break;
 }

 //get copy/ref of the texture
 //uint8_t* data = WindowManager::Get().GetWindow(RtspStreaming::WindowId())->GetBuffer();
 if (!WindowManager::Get().GetWindow(RtspStreaming::WindowId())->GetPixels(data, 0, 0, width, height))
 {
 Debug::Error("Failed to get frame buffer. ID: ", RtspStreaming::WindowId());
 std::this_thread::sleep_for (std::chrono::seconds(2));
 continue;
 }
 //printf("got pixels data\n");
 // convert BGRA to yuv420 pixel format
 int srcStrides[1] = { 4 * width };
 if (sws_scale(conversion_ctx, &data, srcStrides, 0, height, frame->data, frame->linesize) < 0)
 {
 Debug::Error("Unable to scale d3d11 texture to frame. ", frame_cnt);
 break;
 }
 //Debug::Log("frame pts: ", frame->pts, " time_base:", av_rescale_q(1, vid_codec_ctx->time_base, vid_stream->time_base));
 frame->pts = frame_cnt++; 
 //frame_cnt++;
 //printf("scale conversion done\n");

 //encode to the video stream
 int ret = avcodec_send_frame(vid_codec_ctx, frame);
 if (ret < 0)
 {
 Debug::Error("Error sending frame to codec context! ",frame_cnt);
 break;
 }

 AVPacket* pkt = av_packet_alloc();
 //av_init_packet(pkt);
 ret = avcodec_receive_packet(vid_codec_ctx, pkt);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
 {
 //av_packet_unref(pkt);
 av_packet_free(&pkt);
 continue;
 }
 else if (ret < 0)
 {
 Debug::Error("Error during receiving packet: ",AVERROR(ret));
 //av_packet_unref(pkt);
 av_packet_free(&pkt);
 break;
 }

 if (pkt->pts == AV_NOPTS_VALUE)
 {
 //Write PTS
 //Duration between 2 frames (us)
 int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(vid_stream->r_frame_rate);
 //Parameters
 pkt->pts = (double)(frame_cnt * calc_duration) / (double)(av_q2d(time_base) * AV_TIME_BASE);
 pkt->dts = pkt->pts;
 pkt->duration = (double)calc_duration / (double)(av_q2d(time_base) * AV_TIME_BASE);
 }
 int64_t pts_time = av_rescale_q(pkt->dts, time_base, time_base_q);
 int64_t now_time = av_gettime() - start_time_av;

 if (pts_time > now_time)
 av_usleep(pts_time - now_time);

 //pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
 //pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
 //pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
 //pkt->pos = -1;

 //write frame and send
 if (av_interleaved_write_frame(ofmt_ctx, pkt)<0)
 {
 Debug::Error("Error muxing packet, frame number:",frame_cnt);
 break;
 }

 //Debug::Log("RTSP streaming...");
 //sstd::this_thread::sleep_for(std::chrono::milliseconds(1000/20));
 //av_packet_unref(pkt);
 av_packet_free(&pkt);
 }

 //av_free_packet(pkt);
 delete[] data;

 /* Write the trailer, if any. The trailer must be written before you
 * close the CodecContexts open when you wrote the header; otherwise
 * av_write_trailer() may try to use memory that was freed on
 * av_codec_close(). */
 av_write_trailer(ofmt_ctx);
 av_frame_unref(frame);
 av_frame_free(&frame);
 printf("streaming thread CLOSED!\n");
}
</int>












Now, this allows me to connect to my rtsp server and maintain the connection. However, on the rtsp client side I am getting either gray or single static frame as shown below :




Would appreciate if you can help with following questions :


- 

- Firstly, why the stream is not working in spite of continued connection to the server and updating frames ?
- Video codec. By default rtsp format uses Mpeg4 codec, is it possible to use h264 ? When I manually set it to AV_CODEC_ID_H264 the program fails at avcodec_open2 with return value of -22.
- Do I need to create and allocate new "AVFrame" and "AVPacket" for every frame ? Or can I just reuse global variable for this ?
- Do I need to explicitly define some code for real-time streaming ? (Like in ffmpeg we use "-re" flag).










Would be great if you can point out some example code for creating livestream. I have checked following resources :


- 

- https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/encode_video.c
- streaming FLV to RTMP with FFMpeg using H264 codec and C++ API to flv.js
- https://medium.com/swlh/streaming-video-with-ffmpeg-and-directx-11-7395fcb372c4








Update


While test I found that I am able to play the stream using ffplay, while it's getting stuck on VLC player. Here is snapshot on the ffplay log




-
-
FFMPEG Presentation Time Stamps (PTS) calculation in RTSP stream
8 décembre 2020, par BadaBudaBuduBelow please find en raw example of my code for your better understanding of what it does. Please note that this is an updated (removed deprecated methods, etc.) example code by myself from the official FFMPEG documentation complemented by my encoder.


/// STD
#include <iostream>
#include <string>

/// FFMPEG
extern "C"
{
 #include <libavformat></libavformat>avformat.h>
 #include <libswscale></libswscale>swscale.h>
 #include <libavutil></libavutil>imgutils.h>
}

/// VideoLib
#include <tools></tools>multimediaprocessing.h>
#include 
#include 
#include <enums></enums>codec.h>
#include <enums></enums>pixelformat.h>

/// OpenCV
#include <opencv2></opencv2>opencv.hpp>

inline static const char *inputRtspAddress = "rtsp://192.168.0.186:8080/video/h264";

int main()
{
 AVFormatContext* formatContext = nullptr;

 AVStream* audioStream = nullptr;
 AVStream* videoStream = nullptr;
 AVCodec* audioCodec = nullptr;
 AVCodec* videoCodec = nullptr;
 AVCodecContext* audioCodecContext = nullptr;
 AVCodecContext* videoCodecContext = nullptr;
 vl::AudioSettings audioSettings;
 vl::VideoSettings videoSettings;

 int audioIndex = -1;
 int videoIndex = -1;

 SwsContext* swsContext = nullptr;
 std::vector frameBuffer;
 AVFrame* frame = av_frame_alloc();
 AVFrame* decoderFrame = av_frame_alloc();

 AVPacket packet;
 cv::Mat mat;

 vl::tools::MultimediaProcessing multimediaProcessing("rtsp://127.0.0.1:8080/stream", vl::configs::rtspStream, 0, vl::enums::EPixelFormat::ABGR);

 // *** OPEN STREAM *** //
 if(avformat_open_input(&formatContext, inputRtspAddress, nullptr, nullptr) < 0)
 {
 std::cout << "Failed to open input." << std::endl;
 return EXIT_FAILURE;
 }

 if(avformat_find_stream_info(formatContext, nullptr) < 0)
 {
 std::cout << "Failed to find stream info." << std::endl;
 return EXIT_FAILURE;
 }

 // *** FIND DECODER FOR BOTH AUDIO AND VIDEO STREAM *** //
 audioCodec = avcodec_find_decoder(AVCodecID::AV_CODEC_ID_AAC);
 videoCodec = avcodec_find_decoder(AVCodecID::AV_CODEC_ID_H264);

 if(audioCodec == nullptr || videoCodec == nullptr)
 {
 std::cout << "No AUDIO or VIDEO in stream." << std::endl;
 return EXIT_FAILURE;
 }

 // *** FIND STREAM FOR BOTH AUDIO AND VIDEO STREAM *** //

 audioIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, &audioCodec, 0);
 videoIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &videoCodec, 0);

 if(audioIndex < 0 || videoIndex < 0)
 {
 std::cout << "Failed to find AUDIO or VIDEO stream." << std::endl;
 return EXIT_FAILURE;
 }

 audioStream = formatContext->streams[audioIndex];
 videoStream = formatContext->streams[videoIndex];

 // *** ALLOC CODEC CONTEXT FOR BOTH AUDIO AND VIDEO STREAM *** //
 audioCodecContext = avcodec_alloc_context3(audioCodec);
 videoCodecContext = avcodec_alloc_context3(videoCodec);

 if(audioCodecContext == nullptr || videoCodecContext == nullptr)
 {
 std::cout << "Can not allocate AUDIO or VIDEO context." << std::endl;
 return EXIT_FAILURE;
 }

 if(avcodec_parameters_to_context(audioCodecContext, formatContext->streams[audioIndex]->codecpar) < 0 || avcodec_parameters_to_context(videoCodecContext, formatContext->streams[videoIndex]->codecpar) < 0)
 {
 std::cout << "Can not fill AUDIO or VIDEO codec context." << std::endl;
 return EXIT_FAILURE;
 }

 if(avcodec_open2(audioCodecContext, audioCodec, nullptr) < 0 || avcodec_open2(videoCodecContext, videoCodec, nullptr) < 0)
 {
 std::cout << "Failed to open AUDIO codec" << std::endl;
 return EXIT_FAILURE;
 }

 // *** INITIALIZE MULTIMEDIA PROCESSING *** //
 std::vector<unsigned char="char"> extraData(audioStream->codecpar->extradata_size);
 std::copy_n(audioStream->codecpar->extradata, extraData.size(), extraData.begin());

 audioSettings.sampleRate = audioStream->codecpar->sample_rate,
 audioSettings.bitrate = audioStream->codecpar->bit_rate,
 audioSettings.codec = vl::enums::EAudioCodec::AAC,
 audioSettings.channels = audioStream->codecpar->channels,
 audioSettings.bitsPerCodedSample = audioStream->codecpar->bits_per_coded_sample,
 audioSettings.bitsPerRawSample = audioStream->codecpar->bits_per_raw_sample,
 audioSettings.blockAlign = audioStream->codecpar->block_align,
 audioSettings.channelLayout = audioStream->codecpar->channel_layout,
 audioSettings.format = audioStream->codecpar->format,
 audioSettings.frameSize = audioStream->codecpar->frame_size,
 audioSettings.codecExtraData = std::move(extraData);

 videoSettings.width = 1920;
 videoSettings.height = 1080;
 videoSettings.framerate = 25;
 videoSettings.pixelFormat = vl::enums::EPixelFormat::ARGB;
 videoSettings.bitrate = 8000 * 1000;
 videoSettings.codec = vl::enums::EVideoCodec::H264;

 multimediaProcessing.initEncoder(videoSettings, audioSettings);

 // *** INITIALIZE SWS CONTEXT *** //
 swsContext = sws_getCachedContext(nullptr, videoCodecContext->width, videoCodecContext->height, videoCodecContext->pix_fmt, videoCodecContext->width, videoCodecContext->height, AV_PIX_FMT_RGBA, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);

 if (const auto inReturn = av_image_get_buffer_size(AV_PIX_FMT_RGBA, videoCodecContext->width, videoCodecContext->height, 1); inReturn > 0)
 {
 frameBuffer.reserve(inReturn);
 }
 else
 {
 std::cout << "Can not get buffer size." << std::endl;
 return EXIT_FAILURE;
 }

 if (const auto inReturn = av_image_fill_arrays(frame->data, frame->linesize, frameBuffer.data(), AV_PIX_FMT_RGBA, videoCodecContext->width, videoCodecContext->height, 1); inReturn < 0)
 {
 std::cout << "Can not fill buffer arrays." << std::endl;
 return EXIT_FAILURE;
 }

 // *** MAIN LOOP *** //
 while(true)
 {
 // Return the next frame of a stream.
 if(av_read_frame(formatContext, &packet) == 0)
 {
 if(packet.stream_index == videoIndex) // Check if it is video packet.
 {
 // Send packet to decoder.
 if(avcodec_send_packet(videoCodecContext, &packet) == 0)
 {
 int returnCode = avcodec_receive_frame(videoCodecContext, decoderFrame); // Get Frame from decoder.

 if (returnCode == 0) // Transform frame and send it to encoder. And re-stream that.
 {
 sws_scale(swsContext, decoderFrame->data, decoderFrame->linesize, 0, decoderFrame->height, frame->data, frame->linesize);

 mat = cv::Mat(videoCodecContext->height, videoCodecContext->width, CV_8UC4, frameBuffer.data(), frame->linesize[0]);

 cv::resize(mat, mat, cv::Size(1920, 1080), cv::INTER_NEAREST);

 multimediaProcessing.encode(mat.data, packet.dts, packet.dts, packet.flags == AV_PKT_FLAG_KEY); // Thise line sends cv::Mat to encoder and re-streams it.

 av_packet_unref(&packet);
 }
 else if(returnCode == AVERROR(EAGAIN))
 {
 av_frame_unref(decoderFrame);
 av_freep(decoderFrame);
 }
 else
 {
 av_frame_unref(decoderFrame);
 av_freep(decoderFrame);

 std::cout << "Error during decoding." << std::endl;
 return EXIT_FAILURE;
 }
 }
 }
 else if(packet.stream_index == audioIndex) // Check if it is audio packet.
 {
 std::vector vectorPacket(packet.data, packet.data + packet.size);

 multimediaProcessing.addAudioPacket(vectorPacket, packet.dts, packet.dts);
 }
 else
 {
 av_packet_unref(&packet);
 }
 }
 else
 {
 std::cout << "Can not send video packet to decoder." << std::endl;
 std::this_thread::sleep_for(std::chrono::seconds(1));
 }
 }

 return EXIT_SUCCESS;
 }
</unsigned></string></iostream>


What does It do ?


It takes a single RTSP stream to decode its data so I can, for example, draw something to its frames or whatever, and then stream it under a different address.


Basically, I am opening the RTSP stream, check if it does contain both audio and video streams, and find a decoder for them. Then I create an encoder to which I will tell how the output stream should look like and that's it.


And this point I will create an endless loop Where I will read all packets coming from the input stream, then decode it does something to it and again encode it and re=stream it.


What is the issue ?


If you take a closer look I am sending both video and audio frame together with lastly received PTS and DTS contained in AVPacket, to the encoder.


The PTS and DTS from the point when I receive the first AVPacket looks for example like this.


IN AUDIO STREAM :




-22783, -21759, -20735, -19711, -18687, -17663, -16639, -15615, -14591, -13567, -12543, -11519, -10495, -9471, -8447, -7423, -6399, -5375, -4351, -3327, -2303, -1279, -255, 769, 1793, 2817, 3841, 4865, 5889, 6913, 7937, 8961, 9985, 11009, 12033, 13057, 14081, 15105, 16129, 17153




As you can see it is every time incremented by 1024 and that is a sample rate of the audio stream. Quite clear here.


IN VIDEO STREAM :




86400, 90000, 93600, 97200, 100800, 104400, 108000, 111600, 115200, 118800, 122400, 126000, 129600, 133200, 136800, 140400, 144000, 147600, 151200, 154800, 158400, 162000, 165600




As you can see it is every time incremented by 3600 but WHY ?. What this number actually mean ?


From what I can understand, those received PTS and DTS are for the following :


DTS should tell the encoder when it should start encoding the frame so the frame in time are in the correct order and not mishmashed.


PTS should say the correct time when the frame should be played/displayed in the output stream so the frame in time are in the correct order and not mishmashed.


What I am trying to achieve ?


As I said I need to restream a RTSP stream. I can not use PTS and DTS which comes from received AVPackets, because at some point it can happen that the input stream can randomly close and I need to open it again. The problem is that when I actually do it, then the PTS and DTS start to generate again from the minus values same as you could see in the samples. I CAN NOT send those "new" PTS and DTS to the encoder because they are now lower than the encoder/muxer expects.


I need to continually stream something (both audio and video), even it is a blank black screen or silent audio. And each frame the PTS and DTS should rise by a specific number. I need to figure out how the increment is calculated.


----------------------------------


The final result should look like a mosaic of multiple input streams in a single output stream. A single input stream (main) has both audio and video and the rest (side) has just video. Some of those streams can randomly close in time and I need to ensure that it will be back again once it is possible.


-
H264 codec encode, decode and write to file
30 novembre 2020, par Алекс АникейI try to use ffmpeg and h264 codec to translate the video in realtime. But at the state of decoding encoded frame, I get some "bad" image.
Init encoder and decoder :


VCSession *vc_new_x264(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data,
 VCSession *vc)
{

// ------ ffmpeg encoder ------
 AVCodec *codec2 = NULL;
 vc->h264_encoder_ctx = NULL;//AVCodecContext type

 codec2 = NULL;
 avcodec_register_all();
 codec2 = avcodec_find_encoder(AV_CODEC_ID_H264);
 if (codec2 == NULL)
 {
 LOGGER_WARNING(log, "h264: not find encoder");
 }

 vc->h264_encoder_ctx = avcodec_alloc_context3(codec2);

 vc->h264_out_pic2 = av_packet_alloc();

 vc->h264_encoder_ctx->bit_rate = 10 *1000 * 1000;
 vc->h264_encoder_ctx->width = 800;
 vc->h264_encoder_ctx->height = 600;

 vc->h264_enc_width = vc->h264_encoder_ctx->width;
 vc->h264_enc_height = vc->h264_encoder_ctx->height;
 vc->h264_encoder_ctx->time_base = (AVRational) {
 1, 30
 };
 vc->h264_encoder_ctx->gop_size = 30;
 vc->h264_encoder_ctx->max_b_frames = 1;
 vc->h264_encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;


 av_opt_set(vc->h264_encoder_ctx->priv_data, "preset", "veryfast", 0);


 av_opt_set(vc->h264_encoder_ctx->priv_data, "annex_b", "1", 0);
 av_opt_set(vc->h264_encoder_ctx->priv_data, "repeat_headers", "1", 0);
 av_opt_set(vc->h264_encoder_ctx->priv_data, "tune", "zerolatency", 0);
 av_opt_set_int(vc->h264_encoder_ctx->priv_data, "zerolatency", 1, 0);

 vc->h264_encoder_ctx->time_base.num = 1;
 vc->h264_encoder_ctx->time_base.den = 1000;

 vc->h264_encoder_ctx->framerate = (AVRational) {
 1000, 40
 };

 AVDictionary *opts = NULL;

 if (avcodec_open2(vc->h264_encoder_ctx, codec2, &opts) < 0) {
 LOGGER_ERROR(log, "could not open codec H264 on encoder");
 }

 av_dict_free(&opts);



 AVCodec *codec = NULL;
 vc->h264_decoder_ctx = NULL;// AVCodecContext - type
 codec = NULL;

 codec = avcodec_find_decoder(AV_CODEC_ID_H264);

 if (!codec) {
 LOGGER_WARNING(log, "codec not found H264 on decoder");
 }

 vc->h264_decoder_ctx = avcodec_alloc_context3(codec);

 if (codec->capabilities & AV_CODEC_CAP_TRUNCATED) {
 vc->h264_decoder_ctx->flags |= AV_CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
 }

 if (codec->capabilities & AV_CODEC_FLAG_LOW_DELAY) {
 vc->h264_decoder_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
 }

 vc->h264_decoder_ctx->flags |= AV_CODEC_FLAG2_SHOW_ALL;

 vc->h264_decoder_ctx->refcounted_frames = 0;

 vc->h264_decoder_ctx->delay = 0;
 vc->h264_decoder_ctx->sw_pix_fmt = AV_PIX_FMT_YUV420P;
 av_opt_set_int(vc->h264_decoder_ctx->priv_data, "delay", 0, AV_OPT_SEARCH_CHILDREN);
 vc->h264_decoder_ctx->time_base = (AVRational) {
 40, 1000
};
 vc->h264_decoder_ctx->framerate = (AVRational) {
 1000, 40
 };

 if (avcodec_open2(vc->h264_decoder_ctx, codec, NULL) < 0) {
 LOGGER_WARNING(log, "could not open codec H264 on decoder");
 }
 vc->h264_decoder_ctx->refcounted_frames = 0;

 return vc;
}



Encoding (in this function i encode frame and for debugging decode and save him in file) :


uint32_t encode_frame_h264_p(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height,
 const uint8_t *y,
 const uint8_t *u, const uint8_t *v, ToxAVCall *call,
 uint64_t *video_frame_record_timestamp,
 int vpx_encode_flags,
 x264_nal_t **nal,
 int *i_frame_size)
{
 AVFrame *frame;
 int ret;
 uint32_t result = 1;

 frame = av_frame_alloc();

 frame->format = call->video->h264_encoder_ctx->pix_fmt;
 frame->width = width;
 frame->height = height;

 ret = av_frame_get_buffer(frame, 32);

 if (ret < 0) {
 LOGGER_ERROR(av->m->log, "av_frame_get_buffer:Could not allocate the video frame data");
 }

 /* make sure the frame data is writable */
 ret = av_frame_make_writable(frame);

 if (ret < 0) {
 LOGGER_ERROR(av->m->log, "av_frame_make_writable:ERROR");
 }

 frame->pts = (int64_t)(*video_frame_record_timestamp);


 // copy YUV frame data into buffers
 memcpy(frame->data[0], y, width * height);
 memcpy(frame->data[1], u, (width / 2) * (height / 2));
 memcpy(frame->data[2], v, (width / 2) * (height / 2));

 // encode the frame
 ret = avcodec_send_frame(call->video->h264_encoder_ctx, frame);

 if (ret < 0) {
 LOGGER_ERROR(av->m->log, "Error sending a frame for encoding:ERROR");
 }


 ret = avcodec_receive_packet(call->video->h264_encoder_ctx, call->video->h264_out_pic2);



 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
 *i_frame_size = 0;
 } else if (ret < 0) {
 *i_frame_size = 0;
 // fprintf(stderr, "Error during encoding\n");
 } else {

 // Decoded encoded frame and save him to file

 saveInFile(call->video->h264_decoder_ctx, frame, call->video->h264_out_pic2, "/home/user/testSave");

 // printf("Write packet %3"PRId64" (size=%5d)\n", call->video->h264_out_pic2->pts, call->video->h264_out_pic2->size);
 // fwrite(call->video->h264_out_pic2->data, 1, call->video->h264_out_pic2->size, outfile);

 global_encoder_delay_counter++;

 if (global_encoder_delay_counter > 60) {
 global_encoder_delay_counter = 0;
 LOGGER_DEBUG(av->m->log, "enc:delay=%ld",
 (long int)(frame->pts - (int64_t)call->video->h264_out_pic2->pts)
 );
 }


 *i_frame_size = call->video->h264_out_pic2->size;
 *video_frame_record_timestamp = (uint64_t)call->video->h264_out_pic2->pts;

 result = 0;
 }

 av_frame_free(&frame);

 return result;

}



Decode and save frame code :


void saveInFile(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, const char *filename)
{
 if (!pkt)
 return;
 char buf[1024];
 int ret;
 static int curNumber = 0;
 ret = avcodec_send_packet(dec_ctx, pkt);
 if (ret < 0 && ret != AVERROR_EOF)
 {
 fprintf(stderr, "Error sending a packet for decoding'\n");
 if ( ret == AVERROR(EAGAIN))
 return;
 if (ret == AVERROR(EINVAL))
 return;
 if (ret == AVERROR(ENOMEM))
 return;

 }

 ret = avcodec_receive_frame(dec_ctx, frame);
 if (ret == AVERROR(EAGAIN) )
 return;
 if (ret == AVERROR_EOF)
 {
 return;
 }
 else if (ret < 0)
 {
 fprintf(stderr, "Error during decoding\n");
 }
 printf("saving frame %3d\n", dec_ctx->frame_number);
 sprintf(buf, "%s%d", filename, curNumber);
 curNumber++;
 pgm_save(frame->data[0], frame->linesize[0], frame->width, frame->height, buf);

}

void pgm_save(unsigned char* buf, int wrap, int xsize, int ysize, char *filename)
{
 FILE *f;
 int i;
 f = fopen(filename, "w");
 fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
 for (i =0; i < ysize; i++)
 fwrite(buf + i* wrap, 1, xsize, f);
 fclose(f);
}



After this manipulation I have smth like that :