简体   繁体   English

FFmpeg 从 H264 比特流解析 NAL

[英]FFmpeg parse NALs from H264 bitstream

I'm able to use FFmpeg to encode a dummy frame into an H264 bitstream.我可以使用 FFmpeg 将虚拟帧编码为 H264 比特流。 What I'd additionally like to do is extract the individual NAL's from the bitstream.我还想做的是从比特流中提取单个 NAL。

From lots of hunting around it seems like using an AVParser and av_parser_parse2 is the way to do it?从大量的搜索来看,似乎使用AVParserav_parser_parse2是这样做的方法吗? I can see the functionality is there in h264_parser.c I just can't work out how to hook it up.我可以在h264_parser.c 中看到该功能,我不知道如何连接它。 Although maybe AVparser only deals in frames and AVBitStreamFilter or something else is needed?虽然可能AVparser只处理帧和AVBitStreamFilter或需要其他东西?

In my example below I am successfully encoding to H264 and transmitting the results over RTP.在下面的示例中,我成功编码为 H264 并通过 RTP 传输结果。 ffplay is able to receive and display the H264 RTP packets it receives so I'm confident the H264 encoding is working correctly. ffplay能够接收和显示它收到的 H264 RTP 数据包,所以我相信 H264 编码工作正常。

#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <sstream>

#include "strutils.h"

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libavutil/time.h>
}

#define WIDTH 640
#define HEIGHT 480
#define FRAMES_PER_SECOND 30
#define RTP_OUTPUT_FORMAT "rtp"
#define RTP_URL "rtp://127.0.0.1:5024"
#define ERROR_LEN 128
#define codecID AVCodecID::AV_CODEC_ID_H264 // AVCodecID::AV_CODEC_ID_VP8;

SwsContext* _swsContext;
AVCodec* _codec;
AVCodecContext* _codecCtx;
AVFormatContext* _formatContext;
AVStream* _rtpOutStream;
char _errorLog[ERROR_LEN];
AVCodecParserContext* _codecParserCtx;

int main()
{
  std::cout << "FFmpeg Encoder and RTP Stream Test" << std::endl;

  av_log_set_level(AV_LOG_DEBUG);

  // Initialise codec context.
  _codec = avcodec_find_encoder(codecID);
  if (_codec == NULL) {
    throw std::runtime_error("Could not find codec for ID " + std::to_string(codecID) + ".");
  }

  _codecCtx = avcodec_alloc_context3(_codec);
  if (!_codecCtx) {
    std::cerr << "Failed to initialise codec context." << std::endl;;
  }

  _codecCtx->width = WIDTH;
  _codecCtx->height = HEIGHT;
  //_codecCtx->bit_rate = 500000;
  _codecCtx->time_base.den = FRAMES_PER_SECOND;
  _codecCtx->time_base.num = 1;
  //_codecCtx->gop_size = 10;
  //_codecCtx->max_b_frames = 1;
  _codecCtx->pix_fmt = AVPixelFormat::AV_PIX_FMT_YUV420P;

  int res = avcodec_open2(_codecCtx, _codec, NULL);
  if (res < 0) {
    std::cerr << "Failed to open codec: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  // Set up a parser to extract NAL's from the H264 bit stream.
  // Note this is not needed for sending the RTP (I need to separate the NALs for another reason).
  _codecParserCtx = av_parser_init(codecID);
  if (!_codecParserCtx) {
    std::cerr << "Failed to initialise codec parser." << std::endl;
  }

  // Initialise RTP output stream.
  AVOutputFormat* fmt = av_guess_format(RTP_OUTPUT_FORMAT, NULL, NULL);
  if (!fmt) {
    std::cerr << "Failed to guess output format for " << RTP_OUTPUT_FORMAT << "." << std::endl;
  }

  res = avformat_alloc_output_context2(&_formatContext, fmt, fmt->name, RTP_URL);
  if (res < 0) {
    std::cerr << "Failed to allocate output context: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  _rtpOutStream = avformat_new_stream(_formatContext, _codec);
  if (!_rtpOutStream) {
    std::cerr << "Failed to allocate output stream." << std::endl;
  }

  res = avio_open(&_formatContext->pb, _formatContext->url, AVIO_FLAG_WRITE);
  if (res < 0) {
    std::cerr << "Failed to open RTP output context for writing: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  res = avcodec_parameters_from_context(_rtpOutStream->codecpar, _codecCtx);
  if (res < 0) {
    std::cerr << "Failed to copy codec parameters to stream: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  res = avformat_write_header(_formatContext, NULL);
  if (res < 0) {
    std::cerr << "Failed to write output header: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  av_dump_format(_formatContext, 0, RTP_URL, 1);

  // Set a dummy frame with a YUV420 image.
  AVFrame* frame = av_frame_alloc();
  frame->format = AVPixelFormat::AV_PIX_FMT_YUV420P;
  frame->width = WIDTH;
  frame->height = HEIGHT;
  frame->pts = 0;

  res = av_frame_get_buffer(frame, 0);
  if (res < 0) {
    std::cerr << "Failed on av_frame_get_buffer: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  res = av_frame_make_writable(frame);
  if (res < 0) {
    std::cerr << "Failed on av_frame_make_writable: " << av_make_error_string(_errorLog, ERROR_LEN, res) << std::endl;
  }

  for (int y = 0; y < HEIGHT; y++) {
    for (int x = 0; x < WIDTH; x++) {
      frame->data[0][y * frame->linesize[0] + x] = x + y + 1 * 3;
    }
  }

  for (int y = 0; y < HEIGHT / 2; y++) {
    for (int x = 0; x < WIDTH / 2; x++) {
      frame->data[1][y * frame->linesize[1] + x] = 128 + y + 2;
      frame->data[2][y * frame->linesize[2] + x] = 64 + y + 5;
    }
  }

  std::cout << "press any key to start the stream..." << std::endl;
  getchar();

  // Start the loop to encode the static dummy frame and output on the RTP stream.
  AVPacket* pkt = av_packet_alloc();
  uint8_t* data{ nullptr };
  int dataSize;

  while (true) {
    int sendres = avcodec_send_frame(_codecCtx, frame);
    if (sendres != 0) {
      std::cerr << "avcodec_send_frame error: " << av_make_error_string(_errorLog, ERROR_LEN, sendres) << std::endl;
    }

    // Read encoded packets.
    int ret = 0;
    while (ret >= 0) {

      ret = avcodec_receive_packet(_codecCtx, pkt);

      if (ret == AVERROR(EAGAIN)) {
        // Encoder needs more data.
        break;
      }
      else if (ret < 0) {
        std::cerr << "Failed to encode frame: " << av_make_error_string(_errorLog, ERROR_LEN, sendres) << std::endl;
        break;
      }
      else {
        std::cout << "Encoded packet pts " << pkt->pts << ", size " << pkt->size << "." << std::endl;
        std::cout << toHex(pkt->data, pkt->data + pkt->size) << std::endl;

        int pktOffset = 0;

        // TODO: Find a way to separate the NALs from the Annex B H264 byte stream in the AVPacket data.
        //AVBitStreamFilter 
        
        while (pkt->size > pktOffset) {
          int bytesRead = av_parser_parse2(_codecParserCtx, _codecCtx, &data, &dataSize, pkt->data + pktOffset, pkt->size - pktOffset, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);

          if (bytesRead == 0) {
            std::cout << "Failed to parse data from packet." << std::endl;
            break;
          }
          else if (bytesRead < 0) {
            std::cerr << "av_parser_parse2 error: " << av_make_error_string(_errorLog, ERROR_LEN, bytesRead) << std::endl;
            break;
          }
          else {
            std::cout << "Codec parser bytes read " << bytesRead << "." << std::endl;
            pktOffset += bytesRead;
          }
        }
      }

      // Write the encoded packet to the RTP stream.
      int sendRes = av_write_frame(_formatContext, pkt);
      if (sendRes < 0) {
        std::cerr << "Failed to write frame to output stream: " << av_make_error_string(_errorLog, ERROR_LEN, sendres) << std::endl;
        break;
      }

      std::cout << "press any key to continue..." << std::endl;
      getchar();
    }

    av_usleep(1000000 / FRAMES_PER_SECOND);

    frame->pts++;
  }

  av_packet_free(&pkt);
  av_frame_free(&frame);
  avcodec_close(_codecCtx);
  avcodec_free_context(&_codecCtx);
  avformat_free_context(_formatContext);

  return 0;
}

The output from the first available frame that contains 4 separate NALs is below (apologies for the size).包含 4 个单独 NAL 的第一个可用帧的输出如下(对大小表示歉意)。 Since the H264 byte stream is using an Annex B format the NALs can be easily extracted, the delimiter being either 00000001 or 000001 .由于 H264 字节流使用附件 B 格式,因此可以轻松提取 NAL,分隔符为00000001000001 If possible I'd rather use the proper FFmpeg way of parsing instead of re-inventing the wheel.如果可能,我宁愿使用正确的 FFmpeg 解析方式而不是重新发明轮子。

FFmpegCppEncodingTest\x64\Debug>FFmpegCppEncodingTest.exe
FFmpeg Encoder and RTP Stream Test
[libx264 @ 00000252de7e2180] using mv_range_thread = 24
[libx264 @ 00000252de7e2180] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 00000252de7e2180] profile High, level 3.0, 4:2:0, 8-bit
[rtp @ 00000252df9d4c80] No default whitelist set
[udp @ 00000252df9d46c0] No default whitelist set
[udp @ 00000252df501440] No default whitelist set
Output #0, rtp, to 'rtp://127.0.0.1:5024':
  Metadata:
    encoder         : Lavf58.49.100
    Stream #0:0, 0, 1/90000: Video: h264 (libx264), 1 reference frame, yuv420p, 640x480 (0x0), 0/1, q=-1--1, 90k tbn
press any key to start the stream...

[libx264 @ 00000252de7e2180] frame=   0 QP=23.20 NAL=3 Slice:I Poc:0   I:1200 P:0    SKIP:0    size=8262 bytes
Encoded packet pts 0, size 8262.
000000016764001eacd940a03da10000030001000003003c0f162d960000000168ebe3cb22c00000010605ffff9ddc45e9bde6d948b7962cd820d923eeef78323634202d20636f726520313631202d20482e3236342f4d5045472d342041564320636f646563202d20436f70796c65667420323030332d32303230202d20687474703a2f2f7777772e766964656f6c616e2e6f72672f783236342e68746d6c202d206f7074696f6e733a2063616261633d31207265663d33206465626c6f636b3d313a303a3020616e616c7973653d3078333a3078313133206d653d686578207375626d653d37207073793d31207073795f72643d312e30303a302e3030206d697865645f7265663d31206d655f72616e67653d3136206368726f6d615f6d653d31207472656c6c69733d31203878386463743d312063716d3d3020646561647a6f6e653d32312c313120666173745f70736b69703d31206368726f6d615f71705f6f66667365743d2d3220746872656164733d3132206c6f6f6b61686561645f746872656164733d3220736c696365645f746872656164733d30206e723d3020646563696d6174653d3120696e7465726c616365643d3020626c757261795f636f6d7061743d3020636f6e73747261696e65645f696e7472613d3020626672616d65733d3320625f707972616d69643d3220625f61646170743d3120625f626961733d30206469726563743d3120776569676874623d31206f70656e5f676f703d3020776569676874703d32206b6579696e743d323530206b6579696e745f6d696e3d3235207363656e656375743d343020696e7472615f726566726573683d302072635f6c6f6f6b61686561643d34302072633d637266206d62747265653d31206372663d32332e302071636f6d703d302e36302071706d696e3d302071706d61783d3639207170737465703d342069705f726174696f3d312e34302061713d313a312e30300080000001658884005fe89f8677b600fd616763bed58622ce7651a4f1cda99202677e71f334ec6194d4a6485e585812544cbac6755f3e5a4908543c2eab60170fc741f23ef68edc93ff16bfa36c98d7549ea2e1f74d1bafe3cedb15a1b08bb86d804455f4f87d5b5c8ac84edabaa228ef41bb002d16db3be5223900e12129b18fd7b186d33d5f2043ad324200f476fb48272ec5cd166e98419f6c1297e6033031f4fa0ecf2ed7d0c6038e1598dc7923d15b4d918f00bbe7e4dc1296494b0bf6f209c3e84b8bd37c0283ec289b865f471aa8f93495c3cc7ed16332f88dc0bc48b5c3801769dee0dd244492271a89202f6d264031de9810eea8098e9075f56b8a375233ec48651e70ceaee5f0d40922762c46f40681dfdf9c3bd54cffc61a7b1c6c030723be13381247f3ff8de05d21d0053b3022815e6c4b236c84940e4a5de6db03b8f1731279c921bf2a0c92ba62000deaea30e23b2067b2da7c6583cc0d81e652c3fb56a8ae4ffed900983481bf7d14a208748d8ba767ed1b5a68b62c8f548ad5d1857c283b9ac4310767f54a06d6341d7a6a0c05bd1493f8b54b1992f0e528030571f494cf9857c419288115cbc872518338ac9497454439fc28632913f04a514653f1dbae98db306f207aef6467e5cbf977f5936880012e69160cdcab02d91d8fcf8d760cb459bec58b688aadcd9704d47d7e335edd0d14552b305148a2b43681adec4ba9320c3d63d7e742d43d77c08c4c9e46c28cb4f2e55f5384227ac138d3eccdc0dd2884075cbb329f37843e09df7a65e2fcc9555e579840c702385d53a97b021074ede6ed5cc56fe5a43e41751de604e4c1397b60463cbe2393ebce670fb6b56ccdd93f05f989376115d72f30d0d1b7956e56d85885d398f88869eb9ec752048429d30b952c5e8cd1dd624f80a3c8102c37e5b05380b10873ea7d3fcee4a4cf78dd653c62102d4428ee7ef401d2cf74e07b23e26a16c9db26ec390d86c504879e25c698992fdb0628ab4ff80d95125d992fd9ab56433d4c3c7f9294bf3f33e60de3019a9881b86c7a84c9e46cd5a2283dafa974652758bf232d401ec692dc14611d0495e804005a35b474cd63b874e9ffa0166133bc167391dc5c36bc18d90bef2bcf6d7df8f960463cbe2393ebce66e3f643b54afe41d1fca0ff7cdb115d72f4598b6746adcadb0b10e828a6133767c69f2273e853a60b41e590f9f0d004f5475f23e098f4122ece175e98d64a25f26ac44dd65c4618f1b779f0d6e57744aee7835729e311a171be863c1b2df729d000335e412e5b62fbdf60c97eedef55c769b947865ba9a3ccad2411722fe24e15c701c1cc7f875310c7f3367f029042ae2fdaaf3b117fbdd61a6f975e3e32184d21b0c2438b63764015d6eb4b010f821af01a58e881351a5d10a3dff7d754665530cb1d6464e122a3b94e2560dcd9704d47d7e32703c820259d65f0b165686d035bd89bcacba5363d7e742d43f3c4d719bb3e27491c85694e9bb54b18bf9f0d0025e4b1344792ed9ed5b705d7b048a19b83341d580440fb417cda076bdc0a5e996c04a96514311fc938cce9866a812810f519e097defb064bf76f7aad7c8b52d052cb12d364571208b917f126ecc75017f88b2a98c40ff2ccfc4c9e4764eaa353dafa99dddf597599569569e0285afe833ce80f471533fb71727714b151f867708d447d86200111e3e23e2fd9193b068ae0cb9a5ed5604295da0df192f72f03d14d6846571208b917f12709726012e63fc3a988208549ae33767c625f3909da846eed67365f369059c1636dae0a30935216cb7d3827f2454180348f111bc34375c81a4a8acc61e862cf9c760a73d1b2e536b2274000a64b3f1fa5e5eab3cbe2393ebce4adce11c6fa605b3e824cf9b622bae5e8cb697eee987ad616245f3e1f132791dd18dc88f6bea73e05acbaccab500712b0ec4306644fc66a0100166af1e219f190b596898bf13a5cd73cb68bb249603bc487705be58118f2f88e4faf39264330a406aa7d4242af01db0fe0b97a337cedada4bb9ebbff66cc9af64f22328a9e981758f76e936edd95a93aa0fc6dae0a30912d9c8d61e6f7eba5924c5e650d462a401104de6ea146111326a9a130356bbb66d927c938ccdb90e80138a51832fc97defb064bf76f7aad8cb052eed750fb787474cced9cbf893765f51b4717eee02cd869eccfc4c9e4471d65654f5dabc0f387ca5fca870c6bab5fd067e1d03bedfe6afa61f4b9fc5f6a725b6ba2ed537b74adae12ba909651c088a0000600e5a99f2c2ab7365c1351f5f8bc12708dafafa28fc183890cb86d035bd89be14b7e32bd7e742d4c22526b8cdd9fa6e3ce42b4a74f0527362fe7c340f2691f998b1cbdd10b5070baf45611282f18cae646e49a07ce550af5930043d728c0bc2e75b43d0d960766000010f3e1648304bef7d8325fbb7bd571aae2117725c06d3b98946899b236ef71520ad12e63fc3a98834a999f8993c88e3acaca9ebb565ad70f94bf950ec373c9f5c146197f3bb6e64793af2190341263531ff0b4fe0202c57d83b392fe164019c487981b169f5e1afb1e5f11c9f5e722c8cf82247f75a8005e681403b61fc172f3171cbf974c3d6b0b13edee334434f5f00568769da8469526b9b359b482b51f04ee5c28e9aa59f0c802badfee1d2f9e3763b47a898260e95e97a865be63dc9ab693f2ae97d43efa556e6cb826a3ebf19956472192b5f9e936cc2ae42f662d2f67343112f6bf6831e2c67b32010b2e43fba2d4bbb5d82a2f239e827e08b8364af2d8ba50dedff0976c07fae005428f34316369d7486cf5fa1527e2f975e3d2910a63961ac0c0942991f5fc2d5f046aa8d41138e574a9bdc81bc735d484b28e05060001e73f1809b8ac1b9b2e09a8fafc5dd73847797a00944c83d522ee32c1e606597a1e1b4590692a93defbf9d4d7c8f297ee447b5f52a7e43d68c7fcb518be0aab61704ffa33eb4f5abbeb8107f9b6b55db1e8902f580c8b4fecd6c350d64fddaf26d110a9a6342f6ab0214aed06f8c9a91292317b355150d133646ddee29f1206be22caa63109a0a953ec9e479209a4b8bdda7ca856b34af4b768e7d240421f04c8d10d0670bb0fef1893c210ee0ad01b47974d53d1b8a0e678e8009b51ad99fdd7dcac5c98aba3e2d7e47f4436f353ea62597b2f812be6d88aeb97a3402edd9a4bb9ebc001ded08bec9e4779a9a3f72afa9df9ee6ca79196a1cfd23c6a1f4e9bfa77dc050b1badbd0ad6c4803812e3e745165c95df8a100b83cf67f30a381b8eb276a188aadcd9704d47d7e2ed445cecdd9f71e27e39091771960f30162056649e6553ffc42192d1d3ec9e478ed9e51f3b1f1e889b59b4ff9695f95b075a0cfc3a8781d1f5fc2f8b508537b01c911aba80e0f7f6ade4db9fe1aa0e09873834aa67fd8aadcd9704d47d7e32711edbb3926513127170da06b7b137c022fe5a2c8349548f64c7c099bb3f37554b410a72bfd2163afba18455199378e17612413c22e64793b84fbb5ae812be93c02295949ddad71eeb37cb5d10ce41dae168a8204bd56797c4727d79c919463a6ddba17833e82a886ec22bae5e630697fa5c6dc8f74633ed16ffb2791e24a693bd45c9b3b8a18f60eda105618af3421474872181d1f5fc2e8bd474277fec0c66eb0fde2b879e4516a2bb46ad25f23642eac000142e36275078416cd9704d47d7e2ee7afcbff150ca08eaa7063090e2c1e60647e9cc67ccaa7ff8847c5a117d93c8f247347ee55f53d5d86b39b32ad445a51bcc4305ef9f4efb80a1638041208ee1ad0941d4d2b5621efabaa0f76e01c83550d89d431155b9b2e09a8fafc5c3835fa1b44bebaa9c848bb8cb07981948b3324f32a9ffe21c3eae2d1d3ec9dbf3c3c61776dad4eea9a7d3960fcb89067ed861230dd1ca200aeb7e14f1dfb161bfccad72cdcb432b63970829f3c27b00000df2ab81fcec556e6cb826a3ebf177e48cfcee0c31399538618487160f303353247e98f5f9d0b5289ee57f64f23bb9cd25b957d379beaca793d093d5bf9491385d866c0cee402002e355d17e5268a85c06a4b7f014325db22fbaffdaec23d71fbae530c5a1021d8148b66e3fb4960463cbe2393ebce45ac55915f9f7dd1f6f827be6d88aeb97955334eb971b723dd1967ea63132791e5ea68dcf6be9dd11380fabfebbc5a20b161a0cfc3590c1b4015d6ef84bdd8990c62578232d46c68a49cd5f4558b48340f84ed466155b9b2e09a8fafc5cb277537e978923b34b35c3681adec4af0c2cca7ccaa7ff885065a5054d7c8f375349dea2e51e37bcd9a7232d2dabe69060fdc28def0f575e6d4b76c944a9033069b846fac6797b7a6e719078ad5f4571e541c2eb2c90ad17b55810a576837c5a37ac08414dee67a508b1b33b672fe24dca3a65ea663fc3a98881d565a117d93b83ec8e51e222fc41ce1a82975e3d2ff540cea18c084b472c802badcd41b0d55a40cde3d59eba888ae543e17d86a1b6d517d00000b0a6c5ca7e420b66cb826a3ebf1779cdcfcee16528d6f1be8c2438b07981960a445ed1641a4aa525ad08e132791e8efdcb3e763e28b0f55cdcccab513335702e0a30f7e01b5a6803f9f1292b5761b0c6f23f7afb0e536891b2e5381680001119c6f453af231598d4563d1d501e9b0a102dfeb01e63855b51bfc9e34d3ff6d3e374183e5c4264143604c9e479df432c3dafa9f26655e93c8cb510ae56f310c19d01f8e1df4e09ef52c9b08268513e566c0f7f6d2364799227d8faf5eb4e1440004b3d1cad00a97aacf2f88e4faf3929fa62c2de6272d268377cdb115d72f46821f7c6e36e47ba31be5a3a7d93c8f0b5349dea2e51fa67cd9a7232d44ac71c5c43067456780201000a575fbb1fc8376f6a12140b88bbdbff4b965cf101a27b80c15c62b9b3b0831a8ce8f76a709d7ec1890bdd092d7891246899b236ef6df88ae7322fddc059b19768b7fd93c8f125349dea2e53d0eb6b369ff2d292ac307ee147482b181d1f5fc2e19331908bf382bce41df292d2ea5c0664239ec62a13eda0b27fd8aadcd9704d47d7e2eda7de728b848caa8a7063090e2c1e603a476231e8b20d25526e4b422fb2791e4ca68fdcabe9be7430897876d082bcc143f10a3a451bc028fafe168614c2cbf2f495f3a136eea1e78a7168e309ea1b8163a9f9082d9b2e09a8fafc5d5330c98fd85c531388f5dc4a65c3681adec4af2386fb74590692a9304fdf17d93c8f00516767b5f526dc85737332ad2c1dc9ec4428e9936420ff357d323cae70bf97cf608456c2b6b48ed379bd8a6709e1f368ce001c5d303a9eb882d9b2e09a8fafc5d505724801b199d77127170da06b7b137f0a3cb5a2c8349549b27c54fb2791e2a6525b957d37706622661db4230e3ceb5382ec34b86675cc8f27819629ce218ece5f088aff6a34d53d1b8a4640000c3e3e119f971afb1e5f11c9f5e724f1ab446bb6b7b6b5c0ebe6d88aeb97a36a94e93a61eb5858a49d7640a6be47a9d372cf9d8f89fafdae6e6655a890ec974e0a30f5fc886b4d007f400eb459bd73ac9a491e5ca105252674b898325fe5ebf5e7dd0800479b39fe02533c25cb0cc5fa025a46db088d7b5a09570d5b4d0f485bb16c38108780d61e730027294a1f1cf8dab11ffff7c41551ee757ddff993a03622a7e10b591b7b4821f2d05baae32b8a930b4e379e82132a25985d6c93ae2af0235fe000369a441a3bca02997c65646ddedbcbd31a1c45954c6207ac1ee132791dc046bfb957d395c7bf9dd7a1278727066b4819f86eb8b30802bade339e9604c0441b117141d0b0299881b0ed7624b62030c7bf94d83b22e60eeb8a033940f44db6271bdc740d6f62572a41d0d5ebf3a16a4fb31e54d7c8eef5dcc4f6bea75d0bad267fcb4a5624799033f0e38614200aeac7eb1e00b011833aa57b3d46dfdc45708dfb5ea55013bdcc857afaaf5bc43259ee1f1bbb0e4170b28e46792896c592d974542088a9c5c979ad60949e0f791761f0874fdd2bde624f15c68f45fbb80b36363cd95f19bb3ad83d3e52758f0b498fe052967620ca8a790035810a3306d00575bf3378cba74c37f2132a7bf7d6445d7e334b282706179595aa7d00c98f0ba24a476a330aadcd9704d47d7e332aae8ae84383e93d8858e8b43681adec4af62c394f9954fff1065bbc21099bb3f2cb68b52d29c9c98408d501ba1052dc0d73409f483de9efa0588b49e7e8b6ae728e2964605c61b8df1127e5420476495ca360059af5f3c3b485308b8007bfc0d2d3da3f5aa9f06c20f3835c1c833efb4cc5ddaeaa6ec3090e2c1e6065be222d68b20d2552872b3b1fb2791e89e6925cabea3cf189b333fe5a896be4e8e0a30d821ded7323c753a8622f4e6edcb5d3e76c98019803097f11b5c46697f9492e677420c6a33a3dda9c28035324a3c1fe8da195150d133646ddee46258dbc8bf770166c8850653ce733f543458aad29d2474c172fb3477691e1475843e0994743121c2ec3fd280aa1c987f61f8cbedb048316f2d04708552ec1dfaf0926245c1ce51a6f60e520a26c359e3f6432b2b17262ae8f8b5f5f327f3064e9179fe5a301403b61fc172f2a0680b8b49773d780053fbb1fb2791dd8aaa83cec7c77fb026a67fcb4a8ff92e173d70a34119cd579b52df62e9c8a56b0921e39962f5a67db8a23de7d44d263a875083fda0e22f6ab0214aed06f8c967177686cc19d6e01045c8bf8938951cd1af88b2a98c41308ca9e33767c6f790ed5a5395e8bb11d03d7422a18a911087c1322c7773705d87bf4eb0a223b0717ea440304943372e3ae57c75e8d66820b7c0839589900002536f7667d11f72b17262ae8f8b5f9e5f4d2639748bad7028076c3f82e5e8e1c54f2e987ad61624a9b3b1fb2791ddb2aa83cec7c773e39b333fe5a7ffd4db5e218331a63ba2e64793bc26d7a495017342a35a1e57870405354f05d272be909296e1453e7960463cbe2393ebce495f6d3102303e1e0d028076c3f82e5e8b859171692ee7aefff3663704cdd9f9f9443b5694e57c2d8c740f5d08a8a5244421f04c8be7651c1761ef12800d2ef18c6f62390ff516762980bf6a1d277bb09b3d1b22f40c16ec1023ae59412d95958b9315747c5afb0fdbc6d4b879f7ab413c4376115d72f29c748b8b49773d77ffab31b84c9e4776caaa7f3b1eedac4863cc3b6840cb1677410a3a41e23964015d6ee3bb78f67983aa7cc0eedab1352ed0f9cc7e4ab0000973e1ea1fbc2ab7365c1351f5f8bc2a44d3956d2d7def8df46121c583cc0cab491ef2bd7e742d50c552d78cdd9fb079a6908539368f101d1dd0c231e2c9b0987c13b309e3ee05097e7818efa5a0f136a9988b62ddb8a2bd299e59d3bc687226b91dab720000215fdc2b3fbafb958b9315747c5afcec833f3b69794f52c2b781db0fe0b97a370efbd9a61eb5858a26cd08bec9e4497625634f5dab37e8c05ca56a4ec7868de621833b143bfae64792dd857a3edcdea00e0a45dcee0acd67a3645e894102237ff145402a5eab3cbe2393ebce458e76766ee5f4b54b0af8076c3f82e5e54d098bd749773d7802e160e679ce67f057dd0fa14e4d9e8c078774308353f5940f13409f1059f33ebe002adb44f9832e493b3b512855930686a5afa90594acdaa00357d0ae8811668636e0d4c1afb1e5f11c9f5e722daed4bbb7066e838857c03b61fc172f31daf9d46e36e47ba379d5e9faa7d93c78091aa263c91fe97387ce20ce8715abac1fb851d32f82bc200aeb77204203b5134ba7a5b062ace99deba909651c35085c061940f50ffb155b9b2e09a8fafc5e0738471cdfd08d529c18c2438b07981cc5e7bf2d1641a4aa52b36845f64f23d29d51fb957d4fbc51cd94f232d44a4d3a4ae0a30d56bfd4402002f0bfae4615e86b0b0bd01370d3ecaa1ac59fc7c115884b5cbdc4b60c2d724bcdac218722622c178968dbd95a6528c9dbf72b6ec9acdbebd0c155faabbfb4485787cdb115d72f462c9dbd749773d77ff59b474fb2791dd72aa83cec7c76cd6c35565c778059e51ce0a2f0a053b573f458e1107d59c37d9e02a366f07df791152347ab93847887d8351e360ec8b983bae085aef2ccc6b5899ef71d035bd895e16180cf32a9ffe20ee507b535f23bf5555cf9d8f774578c3f2ffaef0e82d8dad067e1d396148fafe175d894ad41444d0b25f8ba6fc5ad88ebbe31a6d1795863dfca6c1d917307773a84d25785adf5e2feef3e80a69f194550c29083fe8f336f29d3601940893c65f0ec3434117431f33e6d9f046aa13f045c1b2579755d48a7c3544bb5f6f974dc3e954ebb8fee5e5c996a989d3d87d6c8ec4d2311f161ac0d52c645fcd5f4fadb48e09f4347d85a8e5f1c4f4eb53b93f7ea4a12e1cb3e7f6a67c05eff6fc46edd40c960dcd9704d47d7e32ad86c9ab18384e9842ffff0c2438b07980ecec9b43a2c834954a223e3e68869eaf0b8ebf63234f39e1fefbb979b2692b9221831c1a573041ee6251cb86da02b3932b56dcaa8076a37fe67949a863f4c590208b176ea109fad54f8361079c1ae1224a28ffe1b36dc716332d0da06b7b12eedf6fe457afce85aa804d08bc66ecec9d91b92cd9f6a1d5202c71d3af185d246b2040b1a4e99dbe8588a54810e60a1f4a687ef6f29602a586dd3c7b25533eb9a3c6643498399f2d24d240ac0b750858b2b43681adec4bbcc1d29b1ebf3a16a8813e1f132791e4bfb911ed7d4aca11867bc8cb4b2ef0b5fd067e1efb82b242128d562d2785378f1c9d288453b93c593cea732e0ede777c6da51ac9f30d1e3321a4c1ccf9692f53d64b73493290dc8bb8cb07981ca85a601e6553ffc41f57d9f8993c8dae76a63d45ca6962a78cf79196a04605465c1461283133500800b918f95c7b663bebcc0b2ddccd7023fd54a7ea2111a72afbf4446bec797c4727d79c94e032f00155de10b4a1267cdb115d72f297e3cb5b49773d780016a935c66ecfd2821f76b4a72c74ab11c83d74206788175902058755d88bb325d6fd065f6efaea76942d65f4d87e0135eb326b96423ce289e98b3c46b0556e6cb826a3ebf194142092abbc4398da06121c583cc0e3529300f32a9ffe20cb69fa290431f250a3353dafa9d34609a31ff2d421bdc346c2e09f82364fb38aeb7348541a866485d72d7fba7bce39fd4a82468849cc3dd6ad4f2e708304bef7d8325fbb7bd58df51f89dca4adb1208b917f12713df7512e63fc3a98875c2cfb3f1327869de2164c7923d3d1402dbf098d4d8c8a8cb828c250e7e6a010017789be48e069ebc1f7e9e7795f98ac429aefd96200029985f7502097aacf2f88e4faf3912e99289fecfe6c4f80901db0fe0b97a3ab6edada4bb9ebbffd9cff4520863f512ee447b5f53cf7c6b2eb32ad3ff9a479d43ea5f76776dcc8f1e46ceb4ab66182a09feba509c5161edfae23c2c7a84f8911dcdd8331c6ad8f119d1eed4e13a71490f6b568e13c6159600822e45fc49c24ba8db08bf770166c6bfa329e7399f990e43b5694e9953dab9699a3bb380f522210f8264e29328e0bb0fb62ca16b2745d97e6eb81b4cb18de29ec12d38f2e1240b8635b33e88fb958b9315747c5afb2ecb2a9e3127c197c0500ed87f05cbd184e76e2d25dcf5dffef541704c9e478228b4972afa9f01ceb9a59956a0ffdb246eee0a26f08000380a163e7392c9337e8bf763948eea906a289a4aa1f1d503dc4a237ec7905b365c1351f5f8bbdf39d65efbd8778ecd8938b86d035bd895ca1fa5ad1641a4aa49016763f64f23b894d24b957d4f516d36667fcb4a98d2c2b5cb8519f86490bcda96fb071f30ed5b628d92b1f5b3a408545faa47484739200000481fe9d9311db6ab0214aed06f8b90f031073c0e36d1dcc54344cd91b77b8a5cf2f3731fe1d4c41854a54f19bb3f3e1b43b5694e4cf86863a07ae8460f252e4d11e4bd650bb470bb0daa83286f28d8f0a874fcb5776f0babe0ee12bfb91b456000026f171e3f5e32b2b17262ae8f8b5fa2da20bae6e75a63744926ec22bae5e8ea65ef2e987ad61626e5a953ec9e478239a4b72afa76ed8863cc3b68460a25f13e0509471cef1b991e4f1de917e90fa133d793e55aca3735cf718c8ef600008461b169f971afb1e5f11c9f5e725f644d2653d6051c2b481db0fe0b97a377845cfa4bb9ebc004c2cf8bec9e477f39a3b3dafa9e2a3e6ce4ff96a1fe29cf37051846dceedb991e4f121b78440475092b9ab56f1e90c0ecb5f17c1eb143926c05f585a29f5e1afb1e5f11c9f5e725582e772569f4791d3e827886ec22bae5e541fb171692ee7aeffd6ec194f39ccfcb71b9dd694e575bc00e5ee86103178925e409f484a4d4a502c4598b0ac156cef3960965d1aeb9ee3f59f9c6e35244d36d2a6db9e4ee60327b32a1fd9d1e3321a4c1ccf9683e22d4bbb7ff4ecc0c90245dc6583cc056f14463d1641a4aa4989528fd93c8eda5346e7b5f5353b16b391ff2d2a4be5315f04819e7ca49caf36a5bee82a3f594a8dcee9cf2d1072b497c1ea57cb48217e8ed90ad17b55810a576837c5bc86e76b7857035e24432676ce5fc49bb474cbd4cc7f87531056ba91d4d7c8eef5346e7b5f4d5f500c7c876d082be5587b70a3a42ca395fcd5f4e5287583748b5ab1ca688d
Codec parser bytes read 8262, data size 0.
nal: .
[rtp @ 00000252df4ef8c0] Sending NAL 7 of len 24 M=0
[rtp @ 00000252df4ef8c0] Sending NAL 8 of len 6 M=0
[rtp @ 00000252df4ef8c0] Sending NAL 6 of len 673 M=0
[rtp @ 00000252df4ef8c0] Sending NAL 5 of len 7545 M=1
[rtp @ 00000252df4ef8c0] NAL size 7545 > 1460
press any key to continue...

[libx264 @ 00000252de7e2180] frame=   1 QP=23.21 NAL=2 Slice:P Poc:8   I:52   P:101  SKIP:1047 size=482 bytes
Encoded packet pts 4, size 482.
00000001419a246c45fffa5d37ecc1d1a2448b600952115b6c1b9880c2721414b9ad381385c2d2db0c0fc3041714814ca3fbfc1c85bb5cf888b1442cdf4fd78bed0ff15512df4949c046d5ed117d4ca9c2fe8e16d8b2a0ee8e8ca9ef07d709242427eec2e62e7c5ddd87a9cc7c7fa3c97bcf657971f49b92b8be0b5ec4d9de8d8abe9aa061abf1d193ca02fe38a4c37e5ca55fac90c7e3d20a050d0684cf50614872855915c4e51caffc4e16e50cfee7c2f92c574efd752e2493c2cb07447541446f498625f89c0396f244bd0674dac31a45e98cbdd7f1f447bf8c84b2c288e3693bcfc2c1a4c0789fdce4fa71181f99a2911c044284c0e9c801e9e7417fc7a65a6f02f8482bd969a8776ecbfff27f823c294ed9e28c56c1816d0f40d2c009f83beb246f5f22e39375fae6db239e9d560e8370f61653ec068631bfe84c2ba6376d1435ca231555a828d724ac0a38fc7986b92997c1a18940bc569d2c652b836b6d368c84ff7ebee187f31f84e6289aa7987ffe660ea59897174f5266bbb471b3ec50070d29b08ca8c92b8c2987da5e80448e99667627e55996a00c56753f9fc65fa75d742e5e15d89ecb007496045027a101244ea4f27792ef3210023196008043fa7e1ca05aa3b1e4a8a6ac5e384440cb5d11d9ec2d1117473875947c2f1aacc37c
Failed to parse data from packet.
[rtp @ 00000252df4ef8c0] Sending NAL 1 of len 478 M=1
press any key to continue...

[libx264 @ 00000252de7e2180] frame=   2 QP=26.00 NAL=2 Slice:B Poc:4   I:0    P:102  SKIP:1098 size=91 bytes
Encoded packet pts 2, size 91.
00000001419e42789bff42138e8cab7ce34f0aaf2f3fb0c41aac77dad7803c8a422c3668a09d337695ffad27dd3d2a1499cf8812c8873f3308741b44759e97059270a4f8678646dfa543ae4da163dacc33a85b2694e7e3c052a861
Codec parser bytes read 91, data size 0.
nal: .
[rtp @ 00000252df4ef8c0] Sending NAL 1 of len 87 M=1
press any key to continue...

[libx264 @ 00000252de7e2180] frame=   3 QP=28.00 NAL=0 Slice:B Poc:2   I:0    P:74   SKIP:1126 size=82 bytes
Encoded packet pts 1, size 82.
00000001019e6174457f4a9778ce66461da66e887d240ad470ec49fe325654c49141af33481787c812ab8d6e27331c0203d4fe099ef254623da56868fdac9a5e5f4e08ec8ef08390748186902972dbe37080
Failed to parse data from packet.
[rtp @ 00000252df4ef8c0] Sending NAL 1 of len 78 M=1
press any key to continue...

Since you are interested in finding NAL units which are delimited by start codes - you could use find_start_code https://www.ffmpeg.org/doxygen/trunk/h264dec_8h_source.html#l00822 which is not exported.由于您有兴趣查找由起始代码分隔的 NAL 单元 - 您可以使用find_start_code https://www.ffmpeg.org/doxygen/trunk/h264dec_8h_source.html#l00822未导出。 So I would probably copy the ffmpeg code into your project.所以我可能会将 ffmpeg 代码复制到您的项目中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM