Hello,

Hello, I have an issue on implementing hardware encoding on raspberry pi by 
using openmax. The problem is that I always get wrong time stamp in my AVpacket 
even right after it gets initialized, the time stamp was always assigned to be 
634 (seems to be the numerator of time base) and it does not change overtime. I 
have run this code on my another Ubuntu laptop, it doesn't have this issue for 
the printf.

code:

AVPacket pkt;
printf("0-time stamp = %ld, enc = %d/%d st = %d/%d\n", pkt.pts,
            encoder_ctx->time_base.num,encoder_ctx->time_base.den,
            fmt_encoder_ctx->streams[video_stream]->time_base.num,
            fmt_encoder_ctx->streams[video_stream]->time_base.den);
printf("avframe time stamp = %ld\n", sw_frame->pts);
av_init_packet(&pkt);
printf("1-time stamp = %ld, enc = %d/%d st = %d/%d\n", pkt.pts,
            encoder_ctx->time_base.num,encoder_ctx->time_base.den,
            fmt_encoder_ctx->streams[video_stream]->time_base.num,
            fmt_encoder_ctx->streams[video_stream]->time_base.den);

result:

0-time stamp = 634, enc = 1907363872/0 st = 634/19001
1-time stamp = 634, enc = 0/-2147483648 st = 634/19001
...(the printed time stamp is always 634 below)

Regards,
Jinbo Li
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/timestamp.h>
#include <stdio.h>
}
#include <map>
#include <vector>
#include <iostream>
static AVCodecContext *decoder_ctx = NULL;
static AVCodecContext *encoder_ctx = NULL;
static AVFormatContext *fmt_decoder_ctx = NULL;
static AVFormatContext *fmt_encoder_ctx = NULL;
static AVBufferRef *hw_device_ctx = NULL;
AVStream *video = NULL;
static int video_stream = -1;
AVFrame *sw_frame = NULL;
AVFrame *hw_frame = NULL;
AVCodec* outputCodec = NULL;
static int n=0;


typedef struct StreamContext {
    int idx;
    enum AVMediaType type;
    AVCodecContext *decoder_ctx;
    AVCodecContext *encoder_ctx;
    AVStream *st;
} StreamContext;

static std::string get_error(int err){
    std::string ret(AV_ERROR_MAX_STRING_SIZE, '\0');
    av_strerror(err, (char*)ret.data(), ret.size());
    return ret;
}

static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx)
{
    AVBufferRef *hw_frames_ref;
    AVHWFramesContext *frames_ctx = NULL;
    int err = 0;

    if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) {
        fprintf(stderr, "Failed to create VAAPI frame context.\n");
        return -1;
    }

    frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data);
    //frames_ctx->format    = AV_PIX_FMT_VAAPI;
    frames_ctx->format = AV_PIX_FMT_YUV420P;
    frames_ctx->sw_format = AV_PIX_FMT_NV12;
    //frames_ctx->sw_format = AV_PIX_FMT_YUV420P;
    frames_ctx->width     = decoder_ctx->width;
    frames_ctx->height    = decoder_ctx->height;
    frames_ctx->initial_pool_size = 20;
    if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) {
        fprintf(stderr, "Failed to initialize VAAPI frame context."
                "Error code: %s\n",get_error(err).c_str());
        av_buffer_unref(&hw_frames_ref);
        return err;
    }
    ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
    if (!ctx->hw_frames_ctx)
        err = AVERROR(ENOMEM);

    av_buffer_unref(&hw_frames_ref);
    return err;
}

static int sw_decoding(AVPacket *pkt)
{
    int ret = 0;
    // decoding
    ret = avcodec_send_packet(decoder_ctx, pkt);
    if (ret < 0) {
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_send_packet");
        return ret;
    }
    if (!(sw_frame = av_frame_alloc())) {
        ret = AVERROR(ENOMEM);
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "av_frame_alloc");
        goto fail_decoding;
    }

    ret = avcodec_receive_frame(decoder_ctx, sw_frame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
        av_frame_free(&sw_frame);
        return 0;
    } else if (ret < 0) {
        av_frame_free(&sw_frame);
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_receive_frame");
        goto fail_decoding;
    }
    return 0;
fail_decoding:
    av_frame_free(&sw_frame);
    if (ret < 0)
        return ret;

    
}

static int encoding_setup(AVCodec *enc_codec){
    int ret = 0;


    encoder_ctx->framerate=decoder_ctx->framerate;
    encoder_ctx->width=decoder_ctx->width;
    encoder_ctx->height=decoder_ctx->height;

    encoder_ctx->pix_fmt=enc_codec->pix_fmts[0];
    encoder_ctx->time_base = decoder_ctx->time_base;
    printf("tb:%d/%d fr:%d/%d\n", encoder_ctx->time_base.num,
        encoder_ctx->time_base.den,encoder_ctx->framerate.num,
        encoder_ctx->framerate.den);
    
    if ((enc_codec->capabilities & AV_CODEC_CAP_HARDWARE )|| 
        (enc_codec->capabilities & AV_CODEC_CAP_HYBRID )){
        if ((ret = set_hwframe_ctx(encoder_ctx, hw_device_ctx)) < 0) {
            fprintf(stderr, "Failed to set hwframe context.\n");
            return ret;
        }
    }
    

    if (ret = avcodec_open2(encoder_ctx, outputCodec, NULL) < 0){
            fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "Could not open encoder");
            return ret;
    }

    if (!(video = avformat_new_stream(fmt_encoder_ctx, enc_codec))) {
        fprintf(stderr, "Failed to allocate stream for output format.\n");
        ret = AVERROR(ENOMEM);
        goto fail_decoding;
    }
    
    video->time_base = encoder_ctx->time_base;
    ret = avcodec_parameters_from_context(video->codecpar, encoder_ctx);
    if (ret < 0) {
        fprintf(stderr, "Failed to copy the stream parameters. "
                "Error code: %s\n", get_error(ret).c_str());
        goto fail_decoding;
    }
    video->avg_frame_rate=encoder_ctx->framerate;
    
    /* write the stream header */
    if ((ret = avformat_write_header(fmt_encoder_ctx, NULL)) < 0) {
        fprintf(stderr, "Error while writing stream header. "
                "Error code: %s\n", get_error(ret).c_str());
        goto fail_decoding;
    }

    return 0;
fail_decoding:
    //av_frame_free(&sw_frame);
    //av_frame_free(&hw_frame);
    if (ret < 0)
        return ret;

}

static int encoding(AVCodec *enc_codec, AVFrame *sw_frame){
    int ret = 0;
    AVPacket pkt;
    printf("0-time stamp = %ld, enc = %d/%d st = %d/%d\n", pkt.pts,
            encoder_ctx->time_base.num,encoder_ctx->time_base.den,
            fmt_encoder_ctx->streams[video_stream]->time_base.num,
            fmt_encoder_ctx->streams[video_stream]->time_base.den);
    av_init_packet(&pkt);
    printf("1-time stamp = %ld, enc = %d/%d st = %d/%d\n", pkt.pts,
            encoder_ctx->time_base.num,encoder_ctx->time_base.den,
            fmt_encoder_ctx->streams[video_stream]->time_base.num,
            fmt_encoder_ctx->streams[video_stream]->time_base.den);
    if (sw_frame){
        hw_frame = av_frame_alloc();
    }
    //For hw encoding only
    if ((enc_codec->capabilities & AV_CODEC_CAP_HARDWARE )|| 
        (enc_codec->capabilities & AV_CODEC_CAP_HYBRID )){
        if (sw_frame && hw_frame){
            if ((ret = av_hwframe_get_buffer(encoder_ctx->hw_frames_ctx, hw_frame, 0)) < 0) {
                fprintf(stderr, "Error code: %s. %d\n", get_error(ret).c_str(), __LINE__);
                goto end;
            }
            
            if (!hw_frame->hw_frames_ctx) {
                ret = AVERROR(ENOMEM);
                goto end;
            }

            if ((ret = av_hwframe_transfer_data(hw_frame, sw_frame, 0)) < 0) {
                fprintf(stderr, "Error while transferring frame data to surface."
                        "Error code: %s.\n", get_error(ret).c_str());
                goto end;
            }
            hw_frame->pts=sw_frame->pts;
        }
    }
    if ((enc_codec->capabilities & AV_CODEC_CAP_HARDWARE )|| 
        (enc_codec->capabilities & AV_CODEC_CAP_HYBRID )){
        if ((ret = avcodec_send_frame(encoder_ctx, hw_frame)) < 0) {
            fprintf(stderr, "Error during encoding. Error code: %s\n", get_error(ret).c_str());
            goto end;
        }
        //printf("avframe data = %p, size = %d\n",hw_frame->data,hw_frame->linesize);
    }else{
        if ((ret = avcodec_send_frame(encoder_ctx, sw_frame)) < 0) {
            fprintf(stderr, "Error during encoding. Error code: %s\n", get_error(ret).c_str());
            goto end;
        }
        //printf("avframe data = %p, size = %d\n",hw_frame->data,sw_frame->linesize);
    }
    //For hw and sw encoding
    while (1) {
        ret = avcodec_receive_packet(encoder_ctx, &pkt);
        if (ret)
            break;
        //printf("avpacket data = %d, size = %d\n",pkt.data,pkt.size);
        pkt.stream_index = 0;
        if (pkt.pts != AV_NOPTS_VALUE)
               pkt.pts = av_rescale_q(pkt.pts, encoder_ctx->time_base,
                                       fmt_encoder_ctx->streams[video_stream]->time_base);
        if (pkt.dts != AV_NOPTS_VALUE)
                pkt.dts = av_rescale_q(pkt.dts, encoder_ctx->time_base,
                                       fmt_encoder_ctx->streams[video_stream]->time_base);

        printf("2-time stamp = %ld, enc = %d/%d st = %d/%d\n", pkt.pts,
            encoder_ctx->time_base.num,encoder_ctx->time_base.den,
            fmt_encoder_ctx->streams[video_stream]->time_base.num,
            fmt_encoder_ctx->streams[video_stream]->time_base.den);

            
        ret = av_interleaved_write_frame(fmt_encoder_ctx, &pkt);
        if (ret < 0) {
            fprintf(stderr, "Error during writing data to output file. "
                    "Error code: %s\n", get_error(ret).c_str());
            return -1;
        }
    }
end:
    if (ret == AVERROR_EOF)
        return 0;
    ret = ((ret == AVERROR(EAGAIN)) ? 0:-1);
    return ret;
}


int main(int argc, char *argv[])
{
    int ret = 0;
    AVPacket pkt;
    StreamContext *streams;
    AVCodec *dec = NULL;
    av_log_set_level(40);
    //open input file
    printf("open input file\n");
    
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <input file> <encoding codec> <output file> \n", argv[0]);
        return -1;
    }
/*
    if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI,NULL, NULL, 0) < 0) {
        fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", get_error(ret).c_str());
        return ret;
    }
*/
    if ((ret = avformat_open_input(&fmt_decoder_ctx, argv[1], NULL, NULL)) < 0) {
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avformat_open_input");
        return ret;
    }
    
    if ((ret = avformat_find_stream_info(fmt_decoder_ctx, NULL)) < 0) {
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avformat_find_stream_info");
        return ret;
    }

    ret = av_find_best_stream(fmt_decoder_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    if (ret < 0) {
        fprintf(stderr, "Cannot find a video stream in the input file. "
                "Error code: %s\n", get_error(ret).c_str());
        return ret;
    }
    video_stream = ret;

    streams = (StreamContext*)av_mallocz_array(fmt_decoder_ctx->nb_streams, sizeof(*streams));
    if (!streams) {
        ret = AVERROR(ENOMEM);
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "av_mallocz_array");
        return ret;
    }

    if (!dec) {
        ret = AVERROR_DECODER_NOT_FOUND;
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_find_decoder");
        return ret;
    }

    if (!(decoder_ctx = avcodec_alloc_context3(dec))) {
        ret = AVERROR(ENOMEM);
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_alloc_context3");
        return ret;
    }

    video = fmt_decoder_ctx->streams[video_stream];
    if ((ret = avcodec_parameters_to_context(decoder_ctx, video->codecpar)) < 0) {
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_parameters_to_context");
        return ret;
    }

    if (decoder_ctx->codec_type == AVMEDIA_TYPE_VIDEO || decoder_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
        if (decoder_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
            decoder_ctx->framerate = av_guess_frame_rate(fmt_decoder_ctx, video, NULL);
        }

        if ((ret = avcodec_open2(decoder_ctx, dec, NULL)) < 0) {
            fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_open2");
            return ret;
        }
    }

	// check if can find a hw encoder
    const AVCodecDescriptor *descriptor_name;
    //,"omx","qsv","vaapi","videotoolbox"
    std::map<std::string,std::vector<std::string>>map_hw_encoders;
    map_hw_encoders["h264"] = {"nvenc", "qsv","omx", "vaapi", "videotoolbox"};
    map_hw_encoders["hevc"] = {"nvenc","qsv","nvenc","vaapi","videotoolbox"};
    map_hw_encoders["mjpeg"] = {"qsv","vaapi"};
    map_hw_encoders["mpeg2"] = {"qsv","vaapi"};
    map_hw_encoders["vp8"] = {"vaapi"};
    map_hw_encoders["vp9"] = {"vaapi"};
    
    auto it = map_hw_encoders.find(argv[2]);
    if (it != map_hw_encoders.end()){
        for (int i=0 ; i < it->second.size() ; i++){
            if (outputCodec = avcodec_find_encoder_by_name((it->first + "_" + it->second[i]).c_str())){
                std::cout << "Found a hw encoder for " << argv[2] << ", " << 
                    it->first << "_" << it->second[i] << std::endl;
                goto success;
            }
        }
    }
    printf("Could not find a hw encoder for %s!\n"
    "Trying to do sw encoding\n", argv[2]);
    if (!(descriptor_name = avcodec_descriptor_get_by_name(argv[2]))){
        printf("Could not find a descriptor by name\n");
        ret= -1;
        goto end;
    }
    if (!(outputCodec = avcodec_find_encoder(descriptor_name->id))){
        printf("Could not find a sw encoder by descriptor\n");
        ret= -1;
        goto end;
    }
    else
        printf("sw encoder for %s is found\n", argv[2]);

success:
    if ((ret = (avformat_alloc_output_context2(&fmt_encoder_ctx, NULL, NULL, argv[3]))) < 0) {
        fprintf(stderr, "Failed to deduce output format from file extension. Error code: "
            "%s\n", get_error(ret).c_str());
    goto end;
    }

    encoder_ctx = avcodec_alloc_context3(outputCodec);
    if (!encoder_ctx) {
        ret = AVERROR(ENOMEM);
        fprintf(stderr, "Got %s in %s\n", get_error(ret).c_str(), "avcodec_alloc_context3");
        return ret;
    }

    ret = avio_open(&fmt_encoder_ctx->pb, argv[3], AVIO_FLAG_WRITE);
    if (ret < 0) {
        fprintf(stderr, "Cannot open output file. "
            "Error code: %s\n", get_error(ret).c_str());
        goto end;
    }

    printf("encoder for %s has been opened\n", argv[2]);

    // hw encoder setup
    encoding_setup(outputCodec);
    printf("encode: after setup, framerate: %d/%d\n",encoder_ctx->framerate.num,encoder_ctx->framerate.den);
    printf("encode: after setup, timebase: %d/%d\n",encoder_ctx->time_base.num,encoder_ctx->time_base.den);
    printf("encode: after setup, width: %d height: %d\n",encoder_ctx->width,encoder_ctx->height);
    printf("encoding setup finished\n");

    while (ret >= 0) {
        if ((ret = av_read_frame(fmt_decoder_ctx, &pkt)) < 0)
            break;

        if ( video_stream == pkt.stream_index){
            sw_decoding(&pkt);
            if (sw_frame)
            sw_frame->pts=n++;
            ret =encoding(outputCodec,sw_frame);
            if (sw_frame)
            av_frame_free(&sw_frame);
            if (hw_frame)
            av_frame_free(&hw_frame);
        }
            
        av_packet_unref(&pkt);
    }
    printf("hw encoding finished\n"
        "flushing started\n");

    /* flush encoder */
    ret = encoding(outputCodec,NULL);
    printf("flush finished\n");

    /* write the trailer for output stream */
    av_write_trailer(fmt_encoder_ctx);
    

end:
    avformat_close_input(&fmt_decoder_ctx);
    avformat_close_input(&fmt_encoder_ctx);
    if (encoder_ctx)
    av_buffer_unref(&encoder_ctx->hw_frames_ctx);
    avcodec_free_context(&decoder_ctx);
    avcodec_free_context(&encoder_ctx);
    av_buffer_unref(&hw_device_ctx);
    av_free(streams);
    return ret;
}

_______________________________________________
Libav-user mailing list
[email protected]
http://ffmpeg.org/mailman/listinfo/libav-user

Reply via email to