winshining / nginx-http-flv-module

A media streaming server based on nginx-rtmp-module. In addtion to the features nginx-rtmp-module provides, HTTP-FLV, GOP cache, VHosts (one IP for multi domain names) and JSON style statistics are supported now.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"invalid video codec header" when streaming from vaapi

SummerOak opened this issue · comments

Hi, I'm using vaapi to encode rawvideo and streamming to the rtmp server like this:

ffmpeg -f rawvideo -pixel_format nv12 -video_size 1280x720 -i - -vaapi_device /dev/dri/renderD128 -vf format=nv12,hwupload -c:v h264_vaapi  -an -f flv rtmp://0.0.0.0:8888/app/test

Since vaapi does't write the global header, the rtmp server won't accept this kind of video stream:

vaapi log:

[h264_vaapi @ 0x60c827752ec0] No global header will be written: this may result in a stream which is not usable for some purposes (e.g. not muxable to some containers).

rtmp server log:

codec: invalid video codec header size=5, client: 127.0.0.1, server: 0.0.0.0:8888

The normal global header is 31 bytes like:

17 00 00 00 00 01 42 40 1F FF E1 00 0A 67 42 40 1F 93 60 28 02 DC 80 01 00 05 68 EE 38 80 00

and the truncated global header is 5 bytes only:

17 00 00 00 00

So I'm going to modify this project to append an default header if no header received:

if (in->buf->last - in->buf->pos < 18) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "codec: invalid video codec header size=%ui",
                      in->buf->last - in->buf->pos);

        ngx_buf_t *b = in->buf;
        if(in->buf->last - in->buf->pos == 5 && b->end - b->last > 31){
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "append a default header for last effort!");
            uint8_t header[26] = {0x01, 0x64, 0x40, 0x1F, 0xFF, 0xE1, 0x00, 0x0A, 0x67, 0x64, 0x40, 0x1F, 0xAC, 0x26, 0xC0, 0x50, 0x05, 0xB9, 0x01, 0x00, 0x05, 0x68, 0xEE, 0x38, 0x80, 0x00};
            ngx_memcpy(b->last, header, sizeof(header));
            *appendHeaderSize = sizeof(header);
            b->last += *appendHeaderSize;
        }else{
            return NGX_ERROR;
        }
    }

But it doesn't work. The stream is accepted now, but the output video stream is malformed and the player can not decode it. Can you help me? thanks!

OS and Nginx version / 操作系统和 Nginx 版本号

nginx version: nginx/1.17.9
kernel: 4.19.105

It seems that there was no SPS(Sequence Parameter Sets) or PPS(Picture Parameter Sets) in your stream, which were necessary for player to initialize decoder. The SPS and PPS are different from one stream to another, so your default constant global header was invalid for player.

It seems that there was no SPS(Sequence Parameter Sets) or PPS(Picture Parameter Sets) in your stream, which were necessary for player to initialize decoder. The SPS and PPS are different from one stream to another, so your default constant global header was invalid for player.

Thanks for your reply!

I was wondering if the code modification for appending default header is correct.( So it is correct?).

The default global header was extracted from the normal stream, just insert a pipe between vaapi and rtmp server:

ffmpeg -f rawvideo -pixel_format nv12 -video_size 1280x720 -i - -vaapi_device /dev/dri/renderD128 -vf format=nv12,hwupload -c:v h264_vaapi  -an -f flv pipe:1 | ffmpeg -i pipe:0 -an -c:v copy -f flv rtmp://0.0.0.0:8888/app/test

Can you tell what is the different between those two kinds of stream?

I'm not sure whether the default header you added was correct or not, but as I said the SPS and PPS are variant from streams to streams, the length is not always 31 besides. 18 is the shortest length needed.

I'm not sure whether the default header you added was correct or not, but as I said the SPS and PPS are variant from streams to streams, the length is not always 31 besides. 18 is the shortest length needed.

Finally I find the reason: The NALU in normal stream(pipe converted) is packet in AVCC format while the wrong stream is packet in AnnexB format. 2 kinds of NALU packet format .

My player just assume the stream is packet in AVCC format.

It seems that there was no SPS(Sequence Parameter Sets) or PPS(Picture Parameter Sets) in your stream, which were necessary for player to initialize decoder. The SPS and PPS are different from one stream to another, so your default constant global header was invalid for player.

Thanks for your reply!

I was wondering if the code modification for appending default header is correct.( So it is correct?).

The default global header was extracted from the normal stream, just insert a pipe between vaapi and rtmp server:

ffmpeg -f rawvideo -pixel_format nv12 -video_size 1280x720 -i - -vaapi_device /dev/dri/renderD128 -vf format=nv12,hwupload -c:v h264_vaapi  -an -f flv pipe:1 | ffmpeg -i pipe:0 -an -c:v copy -f flv rtmp://0.0.0.0:8888/app/test

Can you tell what is the different between those two kinds of stream?

it is work, but I think it is heavy, because we will run two ffmpeg program. @SummerOak