From images to ts

For the developers that use FFmpeg in their software.
Post Reply
Liuhongbo
Posts: 1
Joined: Fri Jan 26, 2018 9:31 am

From images to ts

Post by Liuhongbo » Fri Jan 26, 2018 9:57 am

Hi, all

I wish to encode a list of PNG images (with 4 channels) to a video while streaming it as a TS stream, but when i open the ts file with a general video player, the Last Two frames cannot be shown. But when i open it with StreamEye, all frames can be represented. I don't know what will results it, the C code as following:

Code: Select all

extern "C"
{
//#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
#include "libavutil/timestamp.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h"
};

#define PNG_PATH "./tempPNG/"
#define FRAME_NUM 54
#define TS_FPS 1
#define STREAMING_BUFFER_SIZE (188) 

#define STREAM_PIX_FMT    AV_PIX_FMT_YUV420P /* default pix_fmt */
#define SCALE_FLAGS SWS_BICUBIC

int test_write_buffer(void* opaque, uint8_t* buf, int buf_size)
{
	FILE* fp = NULL;
	char path[256] = { 0 };
	sprintf(path, "%stest123.ts", PNG_PATH);
	fp = fopen(path, "ab+");
	fwrite(buf, 1, buf_size, fp);
	fclose(fp);
	return 1;
}

void main() 
{
    AVFormatContext* pFormatCtx = NULL;
    AVOutputFormat* pOutputFmt = NULL;
    AVCodec* pCodec = NULL;
    AVStream* pStream = NULL;
    AVCodecContext* pCodecCtx = NULL;

    av_register_all();

/****************************************** Format Setting *****************************************/
    avformat_alloc_output_context2(&pFormatCtx, NULL, "mpegts", NULL);
    if (!pFormatCtx) {
        ffmDug("Could not create output context");
        exit(1);
    }

    ffmDug("Format: %s", pFormatCtx->oformat->long_name);

    uint8_t* outbuffer = (uint8_t*)av_malloc(STREAMING_BUFFER_SIZE);
    AVIOContext *avio_out = avio_alloc_context(outbuffer, STREAMING_BUFFER_SIZE, 1, NULL, NULL,
                            temp_write_packet, NULL);
    pFormatCtx->pb = avio_out;
    pFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;

/****************************************** Stream setting ***************************************/
    // Build output stream
    pStream = avformat_new_stream(pFormatCtx, 0);
    if (!pStream) {
        ffmDug("Failed allocating output stream");
        exit(1);
    }
//    pStream->id = pFormatCtx->nb_streams - 1;

    // Find the registered encoder for codec_id(AV_CODEC_ID_*)
    pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!pCodec) {
        ffmDug("Could not find encoder for H264");
        exit(1);
    }

    // Allocate memory for Codec Context to hold the context for encode process
    pCodecCtx = avcodec_alloc_context3(pCodec);

    pStream->codec = pCodecCtx;
    pStream->codec->codec_tag = 0;
    if (pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
        pStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

    pCodecCtx->width = 1280;
    pCodecCtx->height = 720;
    pCodecCtx->bit_rate = 400000;
    pCodecCtx->codec_id = AV_CODEC_ID_H264;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->time_base = (AVRational){1, TS_FPS};

    pStream->time_base = (AVRational){1, TS_FPS};
    pStream->r_frame_rate = (AVRational) {1, TS_FPS};

    pCodecCtx->gop_size = 5;
    pCodecCtx->pix_fmt = STREAM_PIX_FMT;
    pCodecCtx->me_range = 16;
    pCodecCtx->max_qdiff = 4;
    pCodecCtx->qmin = 10;
    pCodecCtx->qmax = 51;
    pCodecCtx->max_b_frames = 0;
    pCodecCtx->refs = 2;
    pCodecCtx->qcompress = 0.6;

    av_opt_set(pCodecCtx->priv_data,"preset","veryfast", 0);
    av_opt_set(pCodecCtx->priv_data,"tune","zerolatency",0);

    // Fill CODEC parameter with codec context
    int ret = avcodec_parameters_from_context(pStream->codecpar, pCodecCtx);
	if (ret < 0)
	{
		ffmDug("Could not copy the stream parameters\n");
		exit(1);
	}

    // Open codec
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        ffmDug("Could not open codec\n");
		exit(1);
    }

    av_dump_format(pFormatCtx, 0, "whatever", 1);

    // Write format header
    ret = avformat_write_header(pFormatCtx, NULL);
	if (ret < 0)
	{
		ffmDug("Error occurred when writing the header\n");
		exit(1);
	}

    // Allocate YUV frame memory
    AVFrame* pFrame = av_frame_alloc();
    if(!pFrame)
	{
		ffmDug("Could not allocate video frame\n");
		exit(1);
	}
	pFrame->format = pCodecCtx->pix_fmt;
	pFrame->width = pCodecCtx->width;
	pFrame->height = pCodecCtx->height;
	ret = av_frame_get_buffer(pFrame, 32);
    if (ret < 0)
	{
		ffmDug("Could not allocate raw picture buffer\n");
		exit(1);
	}

    // Allocate BGRA frame memory
    AVFrame* pFrame_rgba = av_frame_alloc();
    if(!pFrame_rgba)
	{
		ffmDug("Could not allocate rgba frame\n");
		exit(1);
	}
	pFrame_rgba->format = AV_PIX_FMT_BGRA;
	pFrame_rgba->width = pCodecCtx->width;
	pFrame_rgba->height = pCodecCtx->height;
	ret = av_frame_get_buffer(pFrame_rgba, 32);
    if (ret < 0)
	{
		ffmDug("Could not allocate rgba picture buffer\n");
		exit(1);
	}

    struct SwsContext* sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
                                            AV_PIX_FMT_BGRA, pCodecCtx->width,
                                            pCodecCtx->height, STREAM_PIX_FMT,
                                            SCALE_FLAGS, NULL, NULL, NULL);
    if (!sws_ctx)
    {
        ffmDug("Could not initialize the conversion context\n");
        exit(1);
    }

    // Build compressed frame variable
    AVPacket* pkt = av_packet_alloc();

    for (int idx = 0; idx < FRAME_NUM; idx++) {

        char picture[256] = { 0 };
        sprintf(picture, "%s%d.png", PNG_PATH, idx);
        FILE* fp = fopen(picture, "rb");
        if (fp == NULL)
        {
            ffmDug("Failed to open the %d-th image\n", idx);
            fclose(fp);
            exit(1);
        }
        get_png_data(pFrame_rgba, fp);
        fclose(fp);

        sws_scale(sws_ctx, (const uint8_t* const*)pFrame_rgba->data,
			pFrame_rgba->linesize, 0, pCodecCtx->height, pFrame->data,
			pFrame->linesize);
        pFrame->pts = idx;

        // Send the raw data frame to encoder, through the codec context
        ret = avcodec_send_frame(pCodecCtx, pFrame);
        while (ret >= 0) {
            // Receive the raw data packet from encoder,
            // through the same codec context
            ret = avcodec_receive_packet(pCodecCtx, pkt);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                break;
            else if (ret < 0) {
                ffmDug("Error during encoding\n");
                exit(1);
            }

            ffmDug("Write packet %3"PRId64" (size = 5%d)", pkt->pts, pkt->size);
            pkt->stream_index = pStream->index;
            av_packet_rescale_ts(pkt, pCodecCtx->time_base, pStream->time_base);
            av_interleaved_write_frame(pFormatCtx, pkt);
            av_packet_unref(pkt);
        }
    }
    av_write_trailer(pFormatCtx);
}
Can anybody help me?

Thank you very much and Best regards

Post Reply