2016-05-25 32 views
1

我想從通過CCTV相機的SDK API接收的數據包混流到mp4文件的視頻。來自中央電視臺的信息流似乎只包含h264 I和P幀(不包含B幀)。H.264多路複用從CCTV(HW)編碼器MP4,如何獲取AVCodecContext而額外::

的問題是,該文件是不是在Daum的PotPlayer可玩的,當我離開AVCodecContext ::空而額外不過,我可以在VLC播放文件。如果我餵了額外的數據(可能不正確 - 我只是從硬件編碼器接收的數據包中的第一個50個字節複製),該文件是在可玩PotPlayer,但不是在VLC。

我不知道,如何正確地準備而額外。

下面的代碼示出了複用。

void WriteVideo() 
{ 
    AVFormatContext* formatContext = nullptr; 
    AVStream* stream = nullptr; 

    int ret = 0; 

    ret = avformat_alloc_output_context2(&formatContext, nullptr, "mp4", OUTPUT_V_FILE_NAME); 
    if (ret < 0) 
    { 
     fprintf(stderr, "Error occurred when allocating output context: %d\n", ret); 
     return; 
    } 

    stream = avformat_new_stream(formatContext, nullptr); 
    if (!stream) 
    { 
     avformat_free_context(formatContext); 
     formatContext = nullptr; 
     fprintf(stderr, "Error occurred creating new stream"); 
     return; 
    } 

    stream->codec->codec_tag = 0; 

    if (formatContext->oformat->flags & AVFMT_GLOBALHEADER) 
    { 
     stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 
    } 


    stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; 
    stream->codec->codec_id = AV_CODEC_ID_H264; 
    stream->codec->pix_fmt = AV_PIX_FMT_YUV420P; 
    stream->codec->bit_rate = 4096000; // 8192000; // 4096000; // 384000; 
    stream->codec->width = 1920; // 352 
    stream->codec->height = 1080; // 288 
    stream->codec->gop_size = 50; 

    AVRational tb; 
    tb.num = 1; 
    tb.den = 25; 
    stream->codec->time_base = tb; 
    //stream->codec->field_order = AVFieldOrder::AV_FIELD_UNKNOWN; 
    //stream->codec->color_primaries = AVColorPrimaries::AVCOL_PRI_BT470BG; 
    //stream->codec->color_trc = AVColorTransferCharacteristic::AVCOL_TRC_GAMMA22; 
    //stream->codec->colorspace = AVColorSpace::AVCOL_SPC_BT470BG; 
    //stream->codec->chroma_sample_location = AVChromaLocation::AVCHROMA_LOC_CENTER; 
    AVRational aratio; 
    aratio.num = 1; 
    aratio.den = 1; 
    stream->codec->sample_aspect_ratio = aratio; 
    // stream->codec->delay = 0; 
    // stream->codec->color_range = AVColorRange::AVCOL_RANGE_MPEG; 

    av_dump_format(formatContext, 0, formatContext->filename, 1); 

    if (!(formatContext->oformat->flags & AVFMT_NOFILE)) 
    { 
     if (avio_open(&formatContext->pb, formatContext->filename, AVIO_FLAG_WRITE) < 0) 
     { 
      avformat_free_context(formatContext); 
      formatContext = nullptr; 
      fprintf(stderr, "Error occurred when opening output file."); 
      return; 

     } 
    } 

    avformat_write_header(formatContext, nullptr); 

    int frameIdx = 0; 
    int pts = 0; 
    int dts = 0; 
    int pkt_pos = 0; 
    int size = static_cast<int>(tmpRawFrameBuffer.size()); 

    AVPacket pkt = { 0 }; 
    av_init_packet(&pkt); 

    while (frameIdx < size) 
    { 
     pkt.data = tmpRawFrameBuffer[frameIdx]; 
     pkt.size = tmpRawFrameSizes[frameIdx]; 

     // debug purphose start 
     FILE* f; 
     char filename[MAX_PATH]; 
     sprintf_s(filename, MAX_PATH, OUTPUT_PACKET_FILE_PATTERN_NAME, frameIdx); 
     auto err = fopen_s(&f, filename, "wb"); 
     if (err != 0) 
     { 
      fprintf(stderr, "Could not open %s\n", OUTPUT_V_FILE_NAME); 
      exit(1); 
     } 

     fflush(stdout); 
     fwrite(pkt.data, 1, pkt.size, f); 
     fclose(f); 
     // debug purphose end 

     if (tmpRawFrameTypes[frameIdx] == VIDEO_I_FRAME) 
     { 
      pkt.flags |= AV_PKT_FLAG_KEY; 
      stream->codec->extradata_size = 50; 
      stream->codec->extradata = (uint8_t*)av_malloc(stream->codec->extradata_size); 
      memcpy(stream->codec->extradata, pkt.data, stream->codec->extradata_size); 
     } 
     pkt.pts = pts++; 
     pkt.dts = dts++; 
     /* rescale output packet timestamp values from codec to stream timebase */ 
     // av_packet_rescale_ts(&pkt, stream->codec->time_base, stream->time_base); 
     pkt.pts = av_rescale_q(pkt.pts, stream->codec->time_base, stream->time_base); 
     pkt.dts = av_rescale_q(pkt.dts, stream->codec->time_base, stream->time_base); 
     pkt.duration = 512; // should be calculated (derived from FPS 25, and 12800) 
     pkt.pos = -1; 
     pkt.stream_index = stream->index; 

     auto ret = av_write_frame(formatContext, &pkt); 
     if (ret < 0) 
     { 
      fprintf(stderr, "Error while writing video frame: %d\n", ret); 
      break; 
     } 
     av_packet_unref(&pkt); 
     ++frameIdx; 
    } 

    if (formatContext) 
    { 
     av_write_trailer(formatContext); 
     if (!(formatContext->oformat->flags & AVFMT_NOFILE)) avio_close(formatContext->pb); // close the output file 
     avformat_free_context(formatContext); 
     formatContext = nullptr; 
    } 
} 

看來,從攝像頭(在tmpRawFrameBuffer矢量緩存)的數據包包含一些頭,但我不能夠分析他們,我不明白標題的含義。

I幀分組的第一字節看起來像轉儲波紋管:

00 00 01 FC 02 19 F0 87 A0 23 73 41 B6 C0 01 00 
00 00 00 01 67 4D 00 2A 95 A8 1E 00 89 F9 61 00 
00 03 00 01 00 00 03 00 32 84 00 00 00 01 68 EE 
3C 80 00 00 00 01 06 E5 01 19 80 00 00 00 01 65 
B8 00 00 08 C7 B0 23 FF F7 80 EE FE 63 B6 FB F5 
... 

第一P幀的第一字節:

00 00 01 FD E5 24 00 00 00 00 00 01 61 E0 22 27 
FF D6 B0 D7 A4 2B 71 6B 19 C5 87 CA BB 8B BF 60 
14 59 B4 00 CC BC 0F C0 9E FD 84 B5 FB C4 83 DB 
5A 8B 80 FC EC D6 33 6D DE 10 96 6F 31 41 86 5C 
D4 22 F9 33 48 5B CE 77 38 17 0C D6 DD C7 6C E8 
... 

下一個P幀的第一字節:

00 00 01 FD 5E 2F 00 00 00 00 00 01 61 E0 42 2F 
FF E7 06 DD 3C 66 26 15 94 93 7A F1 30 8A 6D B8 
AD DD 6B 0F 38 89 1D 1B 5C AC 44 6A D7 D1 21 3B 
E2 29 F8 14 BB 98 1C 06 4D B6 10 BB DB B9 CA 4F 
0B ED B1 A9 06 78 8C EC 06 6D 9F 4F 79 0C 35 5B 
... 

...

開始下一個I幀:

00 00 01 FC 02 19 F0 87 A2 23 73 41 75 89 01 00 
00 00 00 01 67 4D 00 2A 95 A8 1E 00 89 F9 61 00 
00 03 00 01 00 00 03 00 32 84 00 00 00 01 68 EE 
3C 80 00 00 00 01 06 E5 01 1B 80 00 00 00 01 65 
B8 00 00 0F 07 F0 7F F6 6C 69 43 0F F0 28 DF 97 
... 

有誰知道,如何正確填寫extradata?我只是做了第一個50字節的副本,但看起來,這是不正確的。 (澳大利亞)(SPS)(PPS)(I-Slice)(PPS)(P-Slice)(PPS)(P-Slice)...(澳大利亞)(SPS)(PPS)可能的標題是(澳大利亞) (I-快訊)(https://stackoverflow.com/a/20686267/1699328),但是,我不知道,如何爲

stream->codec->extradata 

我試圖得到一些啓示在這個崗位H.264 muxed to MP4 using libavformat not playing back提取數據,但我無法弄清楚什麼是spsFrameLen,ppsFrameLen和spsFrame的值。

合併器(第一和最後一個字節的MP4文件的)結果:

00 00 00 20 66 74 79 70 69 73 6F 6D 00 00 02 00 
69 73 6F 6D 69 73 6F 32 61 76 63 31 6D 70 34 31 
00 00 00 08 66 72 65 65 00 26 2E 6D 6D 64 61 74 
00 00 00 0D FC 02 19 F0 87 A0 23 73 41 B6 C0 01 
00 00 00 00 16 67 4D 00 2A 95 A8 1E 00 89 F9 61 
00 00 03 00 01 00 00 03 00 32 84 00 00 00 04 68 
EE 3C 80 00 00 00 05 06 E5 01 19 80 00 01 C0 87 
65 B8 00 00 08 C7 B0 23 FF F7 80 EE FE 63 B6 FB 
F5 97 A8 6B 48 39 61 99 FD 99 27 41 F2 78 54 EE 
D1 38 8E E8 18 DD 05 E4 BA F4 EB 69 CF 91 5C 34 
... 
... 
... 
95 B8 D8 D4 C3 AF A1 BA AC 28 F0 D4 D4 7C 48 9A 
0C A6 8C 4C 98 00 00 05 1E 6D 6F 6F 76 00 00 00 
6C 6D 76 68 64 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 03 E8 00 00 13 B0 00 01 00 00 01 00 00 
00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 02 00 00 04 48 74 72 61 
6B 00 00 00 5C 74 6B 68 64 00 00 00 03 00 00 00 
00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 13 
B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 40 00 00 00 07 80 00 00 04 38 00 00 00 00 00 
24 65 64 74 73 00 00 00 1C 65 6C 73 74 00 00 00 
00 00 00 00 01 00 00 13 B0 00 00 00 00 00 01 00 
00 00 00 03 C0 6D 64 69 61 00 00 00 20 6D 64 68 
64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 32 
00 00 00 FC 00 55 C4 00 00 00 00 00 2D 68 64 6C 
72 00 00 00 00 00 00 00 00 76 69 64 65 00 00 00 
00 00 00 00 00 00 00 00 00 56 69 64 65 6F 48 61 
6E 64 6C 65 72 00 00 00 03 6B 6D 69 6E 66 00 00 
00 14 76 6D 68 64 00 00 00 01 00 00 00 00 00 00 
00 00 00 00 00 24 64 69 6E 66 00 00 00 1C 64 72 
65 66 00 00 00 00 00 00 00 01 00 00 00 0C 75 72 
6C 20 00 00 00 01 00 00 03 2B 73 74 62 6C 00 00 
00 93 73 74 73 64 00 00 00 00 00 00 00 01 00 00 
00 83 61 76 63 31 00 00 00 00 00 00 00 01 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 80 
04 38 00 48 00 00 00 48 00 00 00 00 00 00 00 01 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 18 FF FF 00 00 00 2D 61 76 63 43 01 4D 00 2A 
FF E1 00 16 67 4D 00 2A 95 A8 1E 00 89 F9 61 00 
00 03 00 01 00 00 03 00 32 84 01 00 04 68 EE 3C 
80 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 
01 00 00 00 7E 00 00 02 00 00 00 00 1C 73 74 73 
73 00 00 00 00 00 00 00 03 00 00 00 01 00 00 00 
33 00 00 00 65 00 00 00 34 73 74 73 63 00 00 00 
00 00 00 00 03 00 00 00 01 00 00 00 3B 00 00 00 
01 00 00 00 02 00 00 00 37 00 00 00 01 00 00 00 
03 00 00 00 0C 00 00 00 01 00 00 02 0C 73 74 73 
7A 00 00 00 00 00 00 00 00 00 00 00 7E 00 01 C0 
C7 00 00 24 EE 00 00 2F 67 00 00 1D 83 00 00 2E 
8F 00 00 30 B6 00 00 2F 44 00 00 2F 50 00 00 34 
6B 00 00 30 BE 00 00 31 0C 00 00 31 E7 00 00 30 
EA 00 00 31 4E 00 00 31 A8 00 00 32 21 00 00 31 
E6 00 00 31 B5 00 00 31 14 00 00 31 AF 00 00 31 
9D 00 00 33 60 00 00 32 11 00 00 32 4C 00 00 31 
F0 00 00 32 91 00 00 43 43 00 00 44 29 00 00 44 
EC 00 00 44 20 00 00 44 86 00 00 45 AD 00 00 47 
47 00 00 46 9F 00 00 46 D9 00 00 47 BE 00 00 48 
CD 00 00 3E 50 00 00 40 98 00 00 41 0E 00 00 40 
43 00 00 41 07 00 00 41 BB 00 00 41 FF 00 00 30 
5E 00 00 33 C7 00 00 34 B7 00 00 33 F1 00 00 33 
0D 00 00 32 DB 00 01 89 86 00 00 3B E1 00 00 3C 
55 00 00 3C 64 00 00 3C B7 00 00 3C FD 00 00 3E 
54 00 00 3E C5 00 00 3E 1C 00 00 3E 94 00 00 3E 
44 00 00 3E D7 00 00 3F CC 00 00 3E D6 00 00 40 
00 00 00 40 4D 00 00 40 04 00 00 3F A9 00 00 40 
82 00 00 41 0F 00 00 41 64 00 00 41 E5 00 00 42 
1E 00 00 42 2C 00 00 42 80 00 00 42 4D 00 00 43 
9F 00 00 43 DA 00 00 44 45 00 00 44 21 00 00 44 
B7 00 00 45 22 00 00 45 E3 00 00 45 BF 00 00 46 
18 00 00 47 4B 00 00 45 05 00 00 47 34 00 00 46 
60 00 00 46 97 00 00 46 66 00 00 46 29 00 00 46 
38 00 00 47 1D 00 00 47 42 00 00 47 18 00 00 47 
13 00 00 46 52 00 00 47 48 00 00 46 F8 00 01 BE 
E3 00 00 3F 56 00 00 3B 32 00 00 38 F8 00 00 37 
56 00 00 36 2D 00 00 35 DA 00 00 34 6B 00 00 3E 
BE 00 00 3E B5 00 00 3F 33 00 00 3F AC 00 00 3F 
38 00 00 42 32 00 01 1B DC 00 01 80 50 00 01 14 
06 00 00 C2 BB 00 00 96 12 00 00 6D EC 00 00 54 
E6 00 00 3A AC 00 00 32 00 00 00 2F 0A 00 00 2D 
F1 00 00 1B 7F 00 00 00 1C 73 74 63 6F 00 00 00 
00 00 00 00 03 00 00 00 30 00 0F DD AB 00 1F 7D 
9E 00 00 00 62 75 64 74 61 00 00 00 5A 6D 65 74 
61 00 00 00 00 00 00 00 21 68 64 6C 72 00 00 00 
00 00 00 00 00 6D 64 69 72 61 70 70 6C 00 00 00 
00 00 00 00 00 00 00 00 00 2D 69 6C 73 74 00 00 
00 25 A9 74 6F 6F 00 00 00 1D 64 61 74 61 00 00 
00 01 00 00 00 00 4C 61 76 66 35 37 2E 32 33 2E 
31 30 30 

非常感謝任何建議。

回答

2

首先,有一些數據是不是視頻流的一部分。你需要弄清楚如何去除這個問題。一切都可以在這裏得到解答:Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream

+0

謝謝,我在寫這個問題之前經歷了幾次你的帖子,但它對我而言仍然不是那麼清楚...... 請問你能更具體些什麼數據不是流的一部分? 我認爲這可以跳過: '00 00 01 FC 02 19 F0 87 A0 23 73 41 B6 C0 01 00 00 00 00 01 67 4D 00 2A 95 A8 1E 00 89 F9 61 00 00 03 00 01 00 00 03 00 32 84 00 00 00 01 68 EE 3C 80 00 00 00 01 06 E5 01 19 80' (第一個I-幀),然而,這個部分也有一些起始碼... 刪除它們不成問題。提前致謝! – Dom

+0

您需要用眼睛解析數據。閱讀數據包並查看數據。你看到一個開始,接下來會發生什麼?這是一項逆向工程工作。 00 00 00 01 67 - >這是一個SPS,你可以通過一眼就知道。 00 00 01 FC - > type 28,那就是undefined。現在尋找一個模式。你可以放棄未知類型的NALU嗎?也許。 – szatmary