C++11 FFMPEG C api h.264编码/MPEG2 ts流问题

C++11 FFMPEG C api h.264编码/MPEG2 ts流问题,c++11,ffmpeg,C++11,Ffmpeg,类原型如下所示: #ifndef _FULL_MOTION_VIDEO_STREAM_H_ #define _FULL_MOTION_VIDEO_STREAM_H_ #include <memory> #include <string> #ifndef INT64_C # define INT64_C(c) (c ## LL) # define UINT64_C(c) (c ## ULL) #endif extern "C" { #include "lib

类原型如下所示:

#ifndef _FULL_MOTION_VIDEO_STREAM_H_
#define _FULL_MOTION_VIDEO_STREAM_H_

#include <memory>
#include <string>

#ifndef INT64_C
# define INT64_C(c) (c ## LL)
# define UINT64_C(c) (c ## ULL)
#endif

extern "C" 
{
    #include "libavutil/opt.h"
    #include "libavcodec/avcodec.h"
    #include "libavutil/channel_layout.h"
    #include "libavutil/common.h"
    #include "libavutil/imgutils.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/samplefmt.h"
    #include "libavformat/avformat.h"

    #include <libavutil/timestamp.h>
    #include <libswscale/swscale.h>
    #include <libswresample/swresample.h>
}

class FMVStream 
{
    public:
        struct OutputStream 
        {
            OutputStream() :
            st(0),
            next_pts(0),
            samples_count(0),
            frame(0),
            tmpFrame(0),
            sws_ctx(0)
            {
            }

            AVStream *st;

            /* pts of the next frame that will be generated */
            int64_t next_pts;
            int samples_count;

            AVFrame *frame;
            AVFrame *tmpFrame;

            struct SwsContext *sws_ctx;
        };

        ///
        /// Constructor
        ///
        FMVStream();

        ///
        /// Destructor
        ///
        ~FMVStream();

        ///
        /// Frame encoder helper function
        ///
        /// Encodes a raw RGB frame into the transport stream
        ///
        int EncodeFrame(uint8_t* frame);

        ///
        /// Frame width setter
        ///
        void setFrameWidth(int width);

        ///
        /// Frame width getter
        ///
        int getFrameWidth() const;

        ///
        /// Frame height setter
        ///
        void setFrameHeight(int height);

        ///
        /// Frame height getter
        ///
        int getFrameHeight() const;

        ///
        /// Stream address setter
        ///
        void setStreamAddress(const std::string& address);

        ///
        /// Stream address getter
        ///
        std::string getStreamAddress() const;

    private:

        ///
        /// Video Stream creation
        ///
        AVStream* initVideoStream(AVFormatContext* oc);

        ///
        /// Raw frame transcoder
        ///
        /// This will convert the raw RGB frame to a raw YUV frame necessary for h.264 encoding
        ///
        void CopyFrameData(uint8_t* src_frame);

        ///
        /// Video frame allocator
        ///
        AVFrame* AllocPicture(PixelFormat pix_fmt, int width, int height);

        ///
        /// Debug print helper function
        ///
        void print_sdp(AVFormatContext **avc, int n);

        ///
        /// Write the frame to the stream
        ///
        int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt);

        ///
        /// initialize the frame data
        ///
        void initFrame();

        // formatting data needed for output streaming and the output container (MPEG 2 TS)
        AVOutputFormat* format;
        AVFormatContext* format_ctx;

        // structure container for our video stream
        OutputStream stream;

        AVIOContext* io_ctx;

        std::string streamFilename;

        int frameWidth;
        int frameHeight;
};

#endif
我知道这个程序可能有很多问题,我对FFMPEG和多媒体编程非常陌生。我使用了通过搜索google/stack overflow找到的许多代码,以达到这一点。该文件的大小很好,但长度为0.04,它告诉我帧/pkt之间的时间戳必须断开,但我不确定如何解决此问题

我试着用ffmpeg-I用ffmpeg.exe检查文件,并输出到一个常规TS。看起来我的代码比我原来打算的工作得多。然而,我只是试着输出一堆全白色的帧

ffmpeg -i test.mpeg test.ts
ffmpeg version N-70125-g6c9537b Copyright (c) 2000-2015 the FFmpeg developers
  built with gcc 4.9.2 (GCC)
  configuration: --disable-static --enable-shared --enable-gpl --enable-version3
 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --ena
ble-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --e
nable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-lib
gsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencor
e-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enabl
e-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-l
ibtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-
libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-l
ibwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --ena
ble-lzma --enable-decklink --enable-zlib
  libavutil      54. 19.100 / 54. 19.100
  libavcodec     56. 26.100 / 56. 26.100
  libavformat    56. 23.104 / 56. 23.104
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 11.101 /  5. 11.101
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100
Input #0, mpegts, from 'test.mpeg':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 24026 kb/s
  Program 1
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
    Stream #0:0[0x100]: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x00
1B), yuv420p, 640x480, 25 fps, 25 tbr, 90k tbn, 50 tbc
File 'test.ts' already exists. Overwrite ? [y/N] y
Output #0, mpegts, to 'test.ts':
  Metadata:
    encoder         : Lavf56.23.104
    Stream #0:0: Video: mpeg2video, yuv420p, 640x480, q=2-31, 200 kb/s, 25 fps,
90k tbn, 25 tbc
    Metadata:
      encoder         : Lavc56.26.100 mpeg2video
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> mpeg2video (native))
Press [q] to stop, [?] for help
frame=    3 fps=0.0 q=2.0 Lsize=       9kB time=00:00:00.08 bitrate= 883.6kbits/
s dup=0 drop=178
video:7kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ove
rhead: 22.450111%

avpicture\u fill
并不像您想象的那样。它不使用来自ptr的数据填充图片,而是使用ptr作为源填充图片。因此,基本上,您是在编码之前清除图像。

在av_数据包上重新缩放(pkt,*时基,st->时基)

您正在使用AvcodeContext::time\u base 您可以改为设置AvcodeContext::framerate

st->time_base.num=1; st->time_base.den=30

st->codec->framerate.num=1; st->codec->framerate.den=30

改为:

st->time_base.num=1; st->time_base.den=30


st->codec->time\u base=st->time\u base

那么,填写AVFrame数据成员的最简单方法是什么?在重新阅读该函数上的doxy之后,我理解了它的功能,但它让我陷入了如何“填充”帧数据的困境。这是另一个问题。每个帖子1个问题:)最简单?对我来说,根本不使用AVPicture结构,只使用原始指针更容易。但这对你来说可能更困难,因为有更多关于直线跨距和刨床格式的概念,你可能需要自己熟悉才能走这条路。我直接使用原始指针进行了一些搜索,我认为这让我走上了正确的方向。我仍在处理的一个问题是,我认为这是一个时间问题。我对大约1000帧的数据进行了编码,但最终还是得到了一个大小合适的文件,但在进行FFMPEG-I转换时,显示的帧数据很少。不到一秒钟,我就应该有几秒钟的数据。我甚至不能开始破译你试图用pts做什么。什么是
this->pic->pts+=av\u rescale\u q(1,this->stream->codec->time\u base,this->stream->time\u base)?我已经更改了代码,使其看起来像这样。this->stream.frame->pts=this->stream.next_pts++;其中frame->next_pts是一个int64_t,它从@0开始递增。我已经这样做了,正如我昨天注意到的一样。在改变这一点之后,我得到了一个非严格单稳态的pts,最终在编码时得到了非单稳态的dts错误。我还原了一些我的PTS代码,并使错误消失,但是,我的PTS/dts仍然有很多问题。[mpegts@0000000000 63B3E0]DTS 1594658816<7638445056故障我将PTS递增器还原为上面发布的代码。我已经创建并发布了测试代码。。。也许如果你看一看,你可以学到一些新的东西。你想实现什么?为什么不尝试官方示例代码:+RGB到YUV转换:
void FMVStream::CopyFrameData(uint8_t* data)
{
    // fill image with our raw RGB data
    //avpicture_alloc((AVPicture*)this->stream.tmpFrame, PIX_FMT_RGB24, this->stream.st->codec->width, this->stream.st->codec->height);

    int numBytes = avpicture_get_size(PIX_FMT_RGB24, this->stream.st->codec->width, this->stream.st->codec->height);

    uint8_t* buffer = (uint8_t*) av_malloc(numBytes * sizeof(uint8_t));

    avpicture_fill((AVPicture*)this->stream.tmpFrame, buffer, PIX_FMT_RGB24, this->stream.st->codec->width, this->stream.st->codec->height);

    for (int y = 0; y < this->stream.st->codec->height; y++) 
    {
        for (int x = 0; x < this->stream.st->codec->width; x++) 
        {
            int offset = 3 * (x + y * this->stream.st->codec->width);
            this->stream.tmpFrame->data[0][offset + 0] = data[x + y * this->stream.st->codec->width]; // R
            this->stream.tmpFrame->data[0][offset + 1] = data[x + y * this->stream.st->codec->width + 1]; // G
            this->stream.tmpFrame->data[0][offset + 2] = data[x + y * this->stream.st->codec->width + 2]; // B
        }
    }

    // convert the RGB frame to a YUV frame using the sws Context
    this->stream.sws_ctx = sws_getContext(this->stream.st->codec->width, this->stream.st->codec->height, PIX_FMT_RGB32, this->stream.st->codec->width, this->stream.st->codec->height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);

    // use the scale function to transcode this raw frame to the correct type
    sws_scale(this->stream.sws_ctx, this->stream.tmpFrame->data, this->stream.tmpFrame->linesize, 0, this->stream.st->codec->height, this->stream.frame->data, this->stream.frame->linesize);
}
int FMVStream::EncodeFrame(uint8_t* data)
{
    AVCodecContext* c = this->stream.st->codec;

    AVRational one;
    one.den = one.num = 1;

    // check to see if we want to keep writing frames we can probably change this to a toggle switch
    if (av_compare_ts(this->stream.next_pts, this->stream.st->codec->time_base, 10, one) >= 0)
    {
        this->stream.frame = nullptr;
    }
    else
    {
        // Convert and load the frame data into the AVFrame struct
        CopyFrameData(data);
    }

    // setup the timestamp stepping
    AVPacket pkt = { 0 };
    av_init_packet(&pkt);
    this->stream.frame->pts = (int64_t)((1.0 / this->stream.st->codec->framerate.den) * 90000.0 * this->stream.next_pts++);

    int gotPacket, out_size, ret;

    out_size = avcodec_encode_video2(c, &pkt, this->stream.frame, &gotPacket);


    if (gotPacket == 1)
    {
        ret = write_frame(this->format_ctx, &c->time_base, this->stream.st, &pkt);
    }
    else
    {
        ret = 0;
    }

    if (ret < 0)
    {
        std::cerr << "Error writing video frame" << std::endl;
    }

    av_free_packet(&pkt);

    return ((this->stream.frame != nullptr) || gotPacket) ? 0 : 1;
}

int FMVStream::write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
    /* rescale output packet timestamp values from codec to stream timebase */
    av_packet_rescale_ts(pkt, *time_base, st->time_base);
    pkt->stream_index = st->index;

    return av_interleaved_write_frame(fmt_ctx, pkt);
}

void FMVStream::setFrameWidth(const int width)
{
    this->frameWidth = width;
}

int FMVStream::getFrameWidth() const
{
    return this->frameWidth;
}

void FMVStream::setFrameHeight(const int height)
{
    this->frameHeight = height;
}

int FMVStream::getFrameHeight() const
{
    return this->frameHeight;
}

void FMVStream::setStreamAddress(const std::string& address)
{
    this->streamFilename = address;
}

std::string FMVStream::getStreamAddress() const
{
    return this->streamFilename;
}
#include "FullMotionVideoStream.h"

#include <iostream>
#include <thread>
#include <chrono>

int main(int argc, char** argv)
{
    FMVStream* fmv = new FMVStream;

    fmv->setFrameWidth(640);
    fmv->setFrameHeight(480);

    std::cout << "Streaming Address: " << fmv->getStreamAddress() << std::endl;

    // create our alternating frame of black and white to test the streaming functionality
    uint8_t white[640 * 480 * sizeof(uint8_t) * 3];
    uint8_t black[640 * 480 * sizeof(uint8_t) * 3];

    std::memset(white, 255, 640 * 480 * sizeof(uint8_t) * 3);
    std::memset(black, 0, 640 * 480 * sizeof(uint8_t)* 3);

    for (auto i = 0; i < 100; i++)
    {
        auto ret = fmv->EncodeFrame(white);

        if (ret != 0)
        {
            std::cerr << "There was a problem encoding the frame: " << i << std::endl;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }

    for (auto i = 0; i < 100; i++)
    {
        auto ret = fmv->EncodeFrame(black);

        if (ret != 0)
        {
            std::cerr << "There was a problem encoding the frame: " << i << std::endl;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }

    delete fmv;
}
[libx264 @ 000000ac95f58440] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2
AVX FMA3 AVX2 LZCNT BMI2
[libx264 @ 000000ac95f58440] profile Constrained Baseline, level 3.0
Output #0, mpegts, to '(null)':
    Stream #0:0: Video: h264 (libx264), yuv420p, 640x480, q=-1--1, 400 kb/s, 30
tbn
SDP:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
t=0 0
a=tool:libavformat 56.23.104
m=video 0 RTP/AVP 96
b=AS:400
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1
a=control:streamid=0

Streaming Address: test.mpeg
[libx264 @ 000000ac95f58440] frame I:45    Avg QP: 0.51  size:  1315
[libx264 @ 000000ac95f58440] frame P:136   Avg QP: 0.29  size:   182
[libx264 @ 000000ac95f58440] mb I  I16..4: 99.7%  0.0%  0.3%
[libx264 @ 000000ac95f58440] mb P  I16..4:  0.1%  0.0%  0.1%  P16..4:  0.1%  0.0
%  0.0%  0.0%  0.0%    skip:99.7%
[libx264 @ 000000ac95f58440] final ratefactor: -68.99
[libx264 @ 000000ac95f58440] coded y,uvDC,uvAC intra: 0.5% 0.5% 0.5% inter: 0.0%
 0.1% 0.1%
[libx264 @ 000000ac95f58440] i16 v,h,dc,p: 96%  0%  3%  0%
[libx264 @ 000000ac95f58440] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu:  1% 10% 85%  0%  3%
 0%  1%  0%  0%
[libx264 @ 000000ac95f58440] i8c dc,h,v,p: 100%  0%  0%  0%
[libx264 @ 000000ac95f58440] ref P L0: 46.8% 25.2% 28.0%
[libx264 @ 000000ac95f58440] kb/s:0.03
ffmpeg -i test.mpeg test.ts
ffmpeg version N-70125-g6c9537b Copyright (c) 2000-2015 the FFmpeg developers
  built with gcc 4.9.2 (GCC)
  configuration: --disable-static --enable-shared --enable-gpl --enable-version3
 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --ena
ble-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --e
nable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-lib
gsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencor
e-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enabl
e-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-l
ibtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-
libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-l
ibwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --ena
ble-lzma --enable-decklink --enable-zlib
  libavutil      54. 19.100 / 54. 19.100
  libavcodec     56. 26.100 / 56. 26.100
  libavformat    56. 23.104 / 56. 23.104
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 11.101 /  5. 11.101
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100
Input #0, mpegts, from 'test.mpeg':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 24026 kb/s
  Program 1
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
    Stream #0:0[0x100]: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x00
1B), yuv420p, 640x480, 25 fps, 25 tbr, 90k tbn, 50 tbc
File 'test.ts' already exists. Overwrite ? [y/N] y
Output #0, mpegts, to 'test.ts':
  Metadata:
    encoder         : Lavf56.23.104
    Stream #0:0: Video: mpeg2video, yuv420p, 640x480, q=2-31, 200 kb/s, 25 fps,
90k tbn, 25 tbc
    Metadata:
      encoder         : Lavc56.26.100 mpeg2video
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> mpeg2video (native))
Press [q] to stop, [?] for help
frame=    3 fps=0.0 q=2.0 Lsize=       9kB time=00:00:00.08 bitrate= 883.6kbits/
s dup=0 drop=178
video:7kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ove
rhead: 22.450111%