Кодирование аудио / видео с помощью ffmpeg

Кодирование аудио / видео с помощью ffmpeg:

Я пытаюсь создать файл AVI с закодированным видео и аудио, используя ffmpeg.

Сначала я создаю файл:

            //define BITRATE 10000000
            //define GOP 300
            //define FPS 60
            //define VIDEOTYPE "avi"

            if (!encoder_->createFile(QFileInfo(*(videoFile_.data())).absoluteFilePath(), targetRect.width(), targetRect.height(), BITRATE*(1000 / FPS), GOP, 1000))    

Буферы инициализируются как:

            audio_outbuf_size = 44100 * 0.005 * 16; //5ms of audio should be encoded, each time this function is called
            audio_outbuf = new uint8_t[audio_outbuf_size];

            outbuf_size = getWidth()*getHeight() * 3;        
            outbuf = new uint8_t[outbuf_size];

Затем добавьте аудио и видео потоки (аудио: CODEC_ID_PCM_S16LE, 16000 кбит / с и 44100 Гц, видео: PIX_FMT_YUV420P)

            void MediaMuxer::addAudioStream(QString fileName, ffmpeg::CodecID codec_id)
            {
                // Add the audio stream
                ffmpeg::AVCodec *encoder = avcodec_find_encoder(codec_id);
                pAudioStream_ = ffmpeg::av_new_stream(pOutputFormatCtx_, 0);
                if (!pAudioStream_) {
                    printf("Could not allocate stream\n");
                    return;
                }

                pAudioCodecCtx_ = pAudioStream_->codec;
                pAudioCodecCtx_->codec_id = codec_id;
                pAudioCodecCtx_->codec_type = ffmpeg::AVMEDIA_TYPE_AUDIO;
                pAudioCodecCtx_->sample_fmt = ffmpeg::AV_SAMPLE_FMT_S16;
                pAudioCodecCtx_->sample_fmt = encoder->sample_fmts[0];
                pAudioCodecCtx_->bit_rate = 16000;
                //pAudioCodecCtx_->bit_rate = 64000;
                pAudioCodecCtx_->sample_rate = N;
                pAudioCodecCtx_->channels = 1;

                pAudioCodecCtx_->time_base.den = FPS;
                pAudioCodecCtx_->time_base.num = 1;

                avcodec_thread_init(pAudioCodecCtx_, 10);

                // some formats want stream headers to be separate
                if (pOutputFormatCtx_->oformat->flags & AVFMT_GLOBALHEADER)
                    pAudioCodecCtx_->flags |= CODEC_FLAG_GLOBAL_HEADER;

                if (av_set_parameters(pOutputFormatCtx_, NULL) < 0)
                {
                    printf("Invalid output format parameters\n");
                    return;
                }

                //ffmpeg::dump_format(pOutputFormatCtx_, 0, fileName.toStdString().c_str(), 1);

                // open_video
                // find the audio encoder
                pAudioCodec_ = avcodec_find_encoder(pAudioCodecCtx_->codec_id);
                if (!pAudioCodec_)
                {
                    printf("codec not found\n");
                    return;
                }
                // open the codec
                if (avcodec_open(pAudioCodecCtx_, pAudioCodec_) < 0)
                {
                    printf("could not open codec\n");
                    return;
                }

                // Allocate memory for output
                if (!initAudioOutputBuf())
                {
                    printf("Can't allocate memory for audio output bitstream\n");
                    return;
                }

                // Allocate the audio frame
                if (!initAudioFrame())
                {
                    printf("Can't init audio frame\n");
                    return;
                }

                if (url_fopen(&pOutputFormatCtx_->pb, fileName.toStdString().c_str(), URL_WRONLY) < 0)
                {
                    printf("Could not open '%s'\n", fileName.toStdString().c_str());
                    return;
                }
                av_write_header(pOutputFormatCtx_);
            }

            void MediaMuxer::addVideoStream(QString fileName)
            {
                // Add the video stream
                pVideoStream_ = ffmpeg::av_new_stream(pOutputFormatCtx_, 0);
                if (!pVideoStream_)
                {
                    printf("Could not allocate stream\n");
                    return;
                }

                pVideoCodecCtx_ = pVideoStream_->codec;
                pVideoCodecCtx_->codec_id = pOutputFormat_->video_codec;
                pVideoCodecCtx_->codec_type = ffmpeg::AVMEDIA_TYPE_VIDEO;

                pVideoCodecCtx_->bit_rate = Bitrate;
                pVideoCodecCtx_->width = getWidth();
                pVideoCodecCtx_->height = getHeight();
                pVideoCodecCtx_->time_base.den = FPS;
                pVideoCodecCtx_->time_base.num = 1;
                pVideoCodecCtx_->gop_size = Gop;
                pVideoCodecCtx_->pix_fmt = ffmpeg::PIX_FMT_YUV420P;

                avcodec_thread_init(pVideoCodecCtx_, 10);

                // some formats want stream headers to be separate
                if (pOutputFormatCtx_->oformat->flags & AVFMT_GLOBALHEADER)
                    pVideoCodecCtx_->flags |= CODEC_FLAG_GLOBAL_HEADER;


                if (av_set_parameters(pOutputFormatCtx_, NULL) < 0)
                {
                    printf("Invalid output format parameters\n");
                    return;
                }

                //ffmpeg::dump_format(pOutputFormatCtx_, 0, fileName.toStdString().c_str(), 1);

                // open_video
                // find the video encoder
                pVideoCodec_ = avcodec_find_encoder(pVideoCodecCtx_->codec_id);
                if (!pVideoCodec_)
                {
                    printf("codec not found\n");
                    return;
                }
                // open the codec
                if (avcodec_open(pVideoCodecCtx_, pVideoCodec_) < 0)
                {
                    printf("could not open codec\n");
                    return;
                }

                // Allocate memory for output
                if (!initOutputBuf())
                {
                    printf("Can't allocate memory for output bitstream\n");
                    return;
                }

                // Allocate the YUV frame
                if (!initFrame())
                {
                    printf("Can't init frame\n");
                    return;
                }

                if (url_fopen(&pOutputFormatCtx_->pb, fileName.toStdString().c_str(), URL_WRONLY) < 0)
                {
                    printf("Could not open '%s'\n", fileName.toStdString().c_str());
                    return;
                }
                av_write_header(pOutputFormatCtx_);
            }

Наконец, я вызываю альтернативно encodeVideo/encodeAudio для кодирования видео и аудио кадров PCM в определенное время записи (pts):

            int MediaMuxer::encodeVideo(const QImage &img, unsigned pts)
            {
                convertImage_sws(img);     // SWS conversion
                pVideoCodecCtx_->coded_frame->pts = pts;  // Set the time stamp
                int out_size = ffmpeg::avcodec_encode_video(pVideoCodecCtx_, outbuf, outbuf_size, ppicture);        
                pVideoCodecCtx_->coded_frame->pts = pts;  // Set the time stamp

                if (out_size > 0)
                {
                    ffmpeg::av_init_packet(&pkt);       
                    if (pVideoCodecCtx_->coded_frame->pts != (0x8000000000000000LL))
                        pkt.pts = av_rescale_q(pVideoCodecCtx_->coded_frame->pts, pVideoCodecCtx_->time_base, pVideoStream_->time_base);
                    if (pVideoCodecCtx_->coded_frame->key_frame)
                        pkt.flags |= AV_PKT_FLAG_KEY;

                    pkt.stream_index = pVideoStream_->index;
                    pkt.data = outbuf;
                    pkt.size = out_size;
                    int ret = ffmpeg::av_interleaved_write_frame(pOutputFormatCtx_, &pkt);      
                    if (ret<0)
                        return -1;

                }
                return out_size;
            }

            int MediaMuxer::encodeAudio(unsigned pts)
            {
                pAudioCodecCtx_->coded_frame->pts = pts;  // Set the time stamp

                // simple sound encoding    
                int16_t samples[220] = { 0 }; // buffer
                int n;                // buffer index
                double Fs = 44100.0;  // sampling frequency

                // Generate audio data
                for (n = 0; n < 220; ++n)   //220 samples (44100*.005sec as the interval between 2 video frames is 10ms)
                    samples[n] = 16383.0 * sin(n*1000.0*2.0*M_PI / Fs); //sine wav

                int  out_size = ffmpeg::avcodec_encode_audio(pAudioCodecCtx_, audio_outbuf, audio_outbuf_size, (const short*)samples);

                pAudioCodecCtx_->coded_frame->pts = pts;  // Set the time stamp

                if (out_size>0)
                {
                    // Packet
                    ffmpeg::AVPacket pkt = { 0 };
                    av_init_packet(&pkt);
                    pkt.data = NULL; // packet data will be allocated by the encoder
                    pkt.size = 0;
                    if (pAudioCodecCtx_->coded_frame->pts != (0x8000000000000000LL))
                        pkt.pts = av_rescale_q(pAudioCodecCtx_->coded_frame->pts, pAudioCodecCtx_->time_base, pAudioStream_->time_base);
                    if (pAudioCodecCtx_->coded_frame->key_frame)
                        pkt.flags |= AV_PKT_FLAG_KEY;

                    pkt.stream_index = pAudioStream_->index;
                    pkt.data = audio_outbuf;

                    pkt.size = out_size;
                    int ret = av_interleaved_write_frame(pOutputFormatCtx_, &pkt);
                    if (ret<0)
                        return -1;
                    av_free_packet(&pkt);
                }       
                //end simple sound encoding

                return pkt.size;
            }

В результате получается хорошее видео с небольшим количеством звука позади (либо обычный звуковой сигнал с регулярными интервалами, но заканчивающийся намного раньше, чем видео, либо непрерывный более длинный звук, который также длится меньше, чем видео).

Я хочу генерировать звуковой сигнал каждый раз, когда вызывается функция encodeAudio() - с нерегулярными интервалами. Я пытался изменить частоту дискретизации, размер буфера, размер pkt и количество выборок, но безуспешно. Я также пытался установить очки в разное время, но это не помогло мне достичь желаемого результата. Может ли кто-нибудь помочь, пожалуйста?

0 ответов

Другие вопросы по тегам