LINUX.ORG.RU

Сообщения Frosty

 

Кодирование видео с помощью libav*

Привет, ЛОР, есть задача сделать несколько функций, которые будут нарезать и склеивать входные видеофайлы с использованием libavcodec и libavformat. Почитал примеры в исходниках ffmpeg, все смотрелось довольно таки просто, написал программку по образу и подобию, вроде даже открывает, декодирует, кодирует и сбрасывает пакеты в выходной файл, но напоролся на такие подводные камни:

1) при попытке поперематывать выходное видео получаю битую картинку вплоть до следующего ключевого кадра, mplayer сыплет такими ворнингами [mpeg4 @ 0x7fcd7bf12b80]warning: first frame is no keyframe.

2) если пытаться кодировать с помощью libx264, то ловлю для каждого кадра такие ворнинги: [libx264 @ 0x167f1c0] non-strictly-monotonic PTS а для первых 50 кадров до кучи еще и [mp4 @ 0x16821c0] pts < dts in stream 0 Выходная статистика битая, например [libx264 @ 0x167f1c0] kb/s:inf

3) получаю на выходе какой то совсем странный битрейт Выставил: 10Mbps CODEC_ID_H264: 723kbps CODEC_ID_MPEG4: 1142kbps

Есть серьезное подозрение, что у меня плохо с матчастью по части форматов и этих самых волшебных PTS и DTS. Буду признателен, если кто нибудь сможет помочь советом.

Исходник программки:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

    AVFormatContext        *in_ctx;
    AVFormatContext        *out_ctx;
    AVCodecContext         *in_codec_ctx;
    AVCodecContext         *out_codec_ctx;
    AVCodec                *in_codec;
    AVCodec                *out_codec;
    AVStream               *video_st;
    int                    videoStream = -1;


int open_input_file(char *filename) {

   // Open video file
    if(av_open_input_file(&in_ctx, filename, NULL, 0, NULL) != 0)
        return -1; // Couldn't open file

    // Retrieve stream information
    if(av_find_stream_info(in_ctx) < 0)
        return -1; // Couldn't find stream information

    // Find the first video stream
    int i;
    for(i = 0; i < in_ctx->nb_streams; i++)
        if(in_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
            break;
        }
    if(videoStream == -1)
        return -1; // Didn't find a video stream

    // Get a pointer to the codec context for the video stream
    in_codec_ctx = in_ctx->streams[videoStream]->codec;

    // Find the decoder for the video stream
    in_codec = avcodec_find_decoder(in_codec_ctx->codec_id);
    if(in_codec == NULL) {
        fprintf(stderr, "Unsupported input codec!\n");
        return -1; // Codec not found
    }
    // Open codec
    if(avcodec_open(in_codec_ctx, in_codec) < 0)
        return -1; // Could not open codec

    return 0;
}

int create_out_file(char *filename) {
    // Allocate output format context
    out_ctx = avformat_alloc_context();
    out_ctx->oformat = av_guess_format(NULL, filename, NULL);
    if (out_ctx->oformat == NULL)
    {
        fprintf(stderr, "Could not guess output format\n");
        exit(1);
    }

    snprintf(out_ctx->filename, sizeof(out_ctx->filename), "%s", filename);

    video_st = av_new_stream(out_ctx, 0);
    if (!video_st) {
        fprintf(stderr, "Could not alloc stream\n");
        exit(1);
    }

    // Set encoding options
    out_codec_ctx = video_st->codec;
    out_codec_ctx->codec_id = CODEC_ID_H264;
    out_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
    out_codec_ctx->bit_rate = 10000000;
    //out_codec_ctx->crf = 10;
    out_codec_ctx->width = in_codec_ctx->width;
    out_codec_ctx->height = in_codec_ctx->height;
    out_codec_ctx->time_base.den = in_codec_ctx->time_base.den;
    out_codec_ctx->time_base.num = in_codec_ctx->time_base.num;
    out_codec_ctx->gop_size = 30;
    out_codec_ctx->pix_fmt = PIX_FMT_YUV420P;
    out_codec_ctx->thread_count = 4;

    if(out_ctx->oformat->flags & AVFMT_GLOBALHEADER)
        out_codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;

    // Find the encoder for the video stream
    out_codec = avcodec_find_encoder(out_codec_ctx->codec_id);
    if(out_codec == NULL) {
        fprintf(stderr, "Unsupported output codec!\n");
        return -1; // Codec not found
    }
    // Open codec
    if(avcodec_open(out_codec_ctx, out_codec) < 0)
        return -1; // Could not open codec

    avio_open(&out_ctx->pb, filename, AVIO_FLAG_WRITE);
    av_write_header(out_ctx);

    return 0;
}

int main(int argc, char **argv) {

    AVFrame                 *picture;
    int                     picture_size;
    AVFrame                 *tmp_picture;
    int                     out_size;
    int                     frame_count = 0;
    int                     frame_finished;
    AVPacket                packet;
    uint8_t                 *buffer;
    struct SwsContext       *img_convert_ctx;
    int                     retval;

    av_register_all();

    if (open_input_file(argv[1]))
        exit(1);
    if (create_out_file(argv[2]))
        exit(1);

    av_dump_format(in_ctx, 0, argv[1], 0);
    av_dump_format(out_ctx, 0, argv[2], 1);

    //Allocate frame for decoding
    tmp_picture = avcodec_alloc_frame();

    //Allocate frame fro encoding
    picture = avcodec_alloc_frame();
    picture_size = avpicture_get_size(out_codec_ctx->pix_fmt, out_codec_ctx->width, out_codec_ctx->height);
    buffer=(uint8_t *)av_malloc(picture_size * sizeof(uint8_t));
    avpicture_fill((AVPicture *)picture, buffer, out_codec_ctx->pix_fmt, out_codec_ctx->width, out_codec_ctx->height);

    //Crate scaler context
    img_convert_ctx = sws_getContext(in_codec_ctx->width,  in_codec_ctx->height,  in_codec_ctx->pix_fmt,
                                    out_codec_ctx->width, out_codec_ctx->height, out_codec_ctx->pix_fmt,
                                    SWS_BICUBIC, NULL, NULL, NULL);
    if (img_convert_ctx == NULL) {
        fprintf(stderr, "Cannot initialize the conversion context\n");
        exit(1);
    }

    av_init_packet(&packet);

    while (av_read_frame(in_ctx, &packet) >= 0) {
        if(packet.stream_index == videoStream) {
            frame_count++;
            printf("Encoding frame %d\n", frame_count);
            //Decode
            retval = avcodec_decode_video2(in_codec_ctx, tmp_picture, &frame_finished, &packet);
            if (retval < 0)
                fprintf(stderr, "Error decoding frame %d\n", frame_count);

            //Scale
            retval = sws_scale(img_convert_ctx, (const uint8_t * const*)tmp_picture->data, tmp_picture->linesize,
                               0, out_codec_ctx->height, picture->data, picture->linesize);
            if (retval < 1)
                fprintf(stderr, "Error scaling frame %d\n", frame_count);

            //Encode
            out_size = avcodec_encode_video(out_codec_ctx, buffer, picture_size, picture);
            if (out_size < 0) {
                fprintf(stderr, "Error encoding frame %d\n", frame_count);
            } else {
            //Write
                if (out_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE)
                    packet.pts = av_rescale_q(out_codec_ctx->coded_frame->pts, out_codec_ctx->time_base, video_st->time_base);
                if (out_codec_ctx->coded_frame->key_frame) {
                    packet.flags |= AV_PKT_FLAG_KEY;
                    printf("frame %d is key\n", frame_count);
                }
                packet.stream_index = video_st->index;
                packet.data = buffer;
                packet.size = out_size;
                av_write_frame(out_ctx, &packet);
            }
        }
    }

    av_write_trailer(out_ctx);


    av_free_packet(&packet);
    av_free(buffer);
    av_free(picture);
    av_free(tmp_picture);
    avcodec_close(in_codec_ctx);
    avcodec_close(out_codec_ctx);
    av_close_input_file(in_ctx);
    avio_close(out_ctx->pb);

    return 0;
}

Frosty ()

[boinc] Ошибка при сборке примера генератора заданий

Начал писать собственный проект на базе боинка, для начала собрал и установил сервер, затем начал писать тестовые приложения. На вопрос в рассылке «а как мне подцеплять ваши библиотеки из этой помоечки исходников и скомпилированных объектников?» получил ответ «скопируй в свою папку с исходниками папки A B C D, заинклюдь их и подцепи руками библиотеки».

Написал заглушку счетной программы, попробовал собрать - прокатило. Попробовал собрать пример генератора заданий - по логам gcc добавил все нужные либы и уперся вот в такие ошибки:

g++ sample_work_generator.cpp -pthread -Wall  -I ../libs/api-x86_64 -I ../libs/lib-x86_64  -I ../libs/db-x86_64 -I ../libs/tools-x86_64 -I ../libs/sched-x86_64 -I /usr/include/mysql/  ../libs/api-x86_64/libboinc_api.a ../libs/lib-x86_64/libboinc.a  ../libs/sched-x86_64/libsched.a ../libs/lib-x86_64/libboinc_crypt.a /usr/lib/libmysqlclient.a -lz -lssl  -o sample_work_generator
../libs/sched-x86_64/libsched.a(libsched_la-boinc_db.o): In function `WORKUNIT::clear()':
/usr/include/bits/string3.h:86: multiple definition of `WORKUNIT::clear()'
../libs/lib-x86_64/libboinc.a(libboinc_la-gui_rpc_client_ops.o):/usr/include/bits/string3.h:107: first defined here
../libs/sched-x86_64/libsched.a(libsched_la-boinc_db.o): In function `RESULT::clear()':
/usr/include/bits/string3.h:86: multiple definition of `RESULT::clear()'
../libs/lib-x86_64/libboinc.a(libboinc_la-gui_rpc_client_ops.o):/usr/include/bits/string3.h:107: first defined here
../libs/sched-x86_64/libsched.a(libsched_la-boinc_db.o): In function `APP_VERSION::clear()':
/usr/include/bits/string3.h:86: multiple definition of `APP_VERSION::clear()'
../libs/lib-x86_64/libboinc.a(libboinc_la-gui_rpc_client_ops.o):/usr/include/bits/string3.h:107: first defined here
../libs/sched-x86_64/libsched.a(libsched_la-boinc_db.o): In function `APP::clear()':
/usr/include/bits/string3.h:86: multiple definition of `APP::clear()'
../libs/lib-x86_64/libboinc.a(libboinc_la-gui_rpc_client_ops.o):/usr/include/bits/string3.h:107: first defined here
collect2: ld returned 1 exit status

Совершенно непонимаю, что тут происходит, в string3.h явно нет определений методов боинка. Гугл молчит, рассылка и форум боинка тоже, знакомые линуксоиды чешут затылок.

Заранее спасибо за помощь.

Frosty ()

RSS подписка на новые темы