2016-05-25 15 views
1

Ich versuche, ein Video zu mp4-Datei von Paketen über SDK-API von CCTV-Kamera empfangen mux. Der Stream von CCTV scheint nur aus Paketen von h264 I- und P-Frames (keine B-Frames) zu bestehen.H.264 Muxing zu MP4 von CCTV (HW) Encoder mit ffmpeg Bibliothek in C/C++, wie AVCodecContext :: extradata

Das Problem ist, dass die Datei im Daum PotPlayer nicht spielbar ist, wenn ich die AVCodecContext :: extradata leer lasse, aber ich kann die Datei in VLC abspielen. Wenn ich die zusätzlichen Daten füttere (wahrscheinlich nicht richtig - ich kopiere nur die ersten 50 Bytes aus dem Paket, das vom HW-Encoder empfangen wurde), ist die Datei im PotPlayer, aber nicht im VLC spielbar.

Ich weiß nicht, wie man die Extradata richtig vorbereitet.

Der folgende Code zeigt das Muxing.

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; 
    } 
} 

Es scheint, enthält das Paket von der Kamera (gepuffert in tmpRawFrameBuffer Vektor) einige Header, aber ich bin sie nicht in der Lage zu analysieren, verstehe ich nicht die Bedeutung des Sammlers.

Das erste Bytes des I-Rahmenpaketes sieht aus wie die Mulden unten:

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 
... 

das erste Bytes des ersten P-Frame:

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 
... 

ersten Bytes des nächsten P-Rahmen :

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 
... 

...

Anfang des nächsten I-Frame:

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 
... 

jemand kennt, wie richtig die Extrainformationen zu füllen? Ich habe gerade eine Kopie der ersten 50 Bytes gemacht, aber es scheint, das ist nicht korrekt.

Wahrscheinlich sind die Header (AUD) (SPS) (PPS) (I-Scheibe) (PPS) (P-Scheibe) (PPS) (P-Scheibe) ... (AUD) (SPS) (PPS) (I-Slice) (https://stackoverflow.com/a/20686267/1699328), aber ich weiß nicht, wie die Daten zu extrahieren, für die

stream->codec->extradata 

ich habe versucht, etwas Inspiration in diesem Beitrag zu erhalten H.264 muxed to MP4 using libavformat not playing back, aber ich bin nicht in der Lage, herauszufinden, was sind Werte von spsFrameLen, ppsFrameLen und spsFrame.

Das Ergebnis der muxer (erste und letzte Byte der mp4-Datei):

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 

Vielen Dank für alle Ratschläge.

Antwort

2

Zunächst gibt es einige Daten, die nicht Teil des Videostreams sind. Sie müssen herausfinden, wie Sie das entfernen können. Alles andere kann hier beantwortet werden: Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream

+0

Danke, ich habe Ihre poste schon einige Male durchgelesen, bevor ich diese Frage geschrieben habe, aber es war und ist noch nicht so klar für mich ... Könnten Sie bitte genauer spezifizieren, welche Daten sind nicht Teil des Streams? Ich denke, das könnte übersprungen werden: 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' (erster I-Rahmen), jedoch gibt es in diesem Teil auch einige Startcodes ... Sie zu entfernen ist kein Problem. Danke im Voraus! – Dom

+0

Sie müssen die Daten mit Ihren Augen analysieren. Lesen Sie das Paket und schauen Sie sich die Daten an. Du siehst einen Start, was kommt als nächstes? Dies ist ein Reverse-Engineering-Job. 00 00 00 01 67 -> Das ist eine SPS, das sieht man, wenn man sie anschaut. 00 00 01 FC -> Typ 28, das ist undefiniert. jetzt nach einem Muster suchen. können Sie einfach NALUs unbekannten Typs löschen? könnte sein. – szatmary