无法在iPhone上播放使用hvc1标签转换的DAV到MP4格式的H.265视频文件。

huangapple go评论170阅读模式
英文:

Cannot play DAV to MP4 converted H.265 video file with hvc1 tag in iPhone

问题

我已经使用以下命令从大华摄像机将H.265视频文件转换为dav格式。生成的两个mp4视频文件在iPhone默认播放器中都无法播放。但是,生成的视频文件可以在VLC播放器中播放。

ffmpeg -y -i hevc.dav -c:v copy -tag:v hvc1 hevc.mp4
ffmpeg -y -i hevc.dav -tag:v hvc1 -c:v copy -f mp4 -movflags frag_keyframe+empty_moov hevc.mp4

只有当我使用以下命令重新编码视频时,生成的视频文件才能播放。

ffmpeg -y -i hevc.dav -c:v libx265 -tag:v hvc1 hevc.mp4

重新编码非常耗时。所以,请告诉我是否在上述命令中漏掉了任何标志。

英文:

I have converted H.265 video file in dav format from Dahua camera using following commands. Both of the generated mp4 video files are NOT playable in iPhone default player. However, the generated video files are playable in VLC player.

ffmpeg -y -i hevc.dav -c:v copy -tag:v hvc1 hevc.mp4
ffmpeg -y -i hevc.dav -tag:v hvc1 -c:v copy -f mp4 -movflags frag_keyframe+empty_moov hevc.mp4

Generated video file plays only if I re-encode the video using following command.

ffmpeg -y -i hevc.dav -c:v libx265 -tag:v hvc1 hevc.mp4

Re-encoding is time consuming. So, please let me know, if I am missing any flags in the above commands.

答案1

得分: 1

解决方案
输入文件在开头(前46KB)有一些额外的字节,位于实际DAV标头之前。 移除这些额外字节 生成了一个新的DAV输出文件,然后FFmpeg会接受并正确地混合成MP4。

未来的读者可以查看以下研究点:

流程
我使用 hexdump -C 命令验证了源 .dav 文件,并发现文件开头的字节不是DHAV。这给了我一个线索,即第一个HEVC帧不完整。

我编写了一个小型C程序来搜索文件中是否还有DHAV字节,我在大约46KB之后找到了DHAV。我从文件开头删除了这些部分字节,并将其余字节写入另一个名为 hevc_cropped_bytes.dav 的文件,然后运行了以下命令。

ffmpeg -y -i hevc_cropped_bytes.dav -c:v copy -tag:v hvc1 hevc.mp4

这次生成的视频文件正常播放。以下是从文件开头删除部分字节的程序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 4096

int main()
{
    FILE *inputFile, *outputFile;
    char signature[] = "DHAV";
    unsigned char buffer[BUF_SIZE];
    unsigned char *ptr;
    int bytesRead;
    int found = 0;

    // 打开输入二进制文件
    inputFile = fopen("hevc.dav", "rb");
    if (inputFile == NULL) {
        perror("打开输入文件时出错");
        return 1;
    }

    // 打开输出二进制文件
    outputFile = fopen("hevc_cropped.dav", "wb");
    if (outputFile == NULL) {
        perror("创建输出文件时出错");
        fclose(inputFile);
        return 1;
    }

    // 读取初始块
    bytesRead = fread(buffer, sizeof(unsigned char), BUF_SIZE, inputFile);

    while (bytesRead > 0) {
        ptr = buffer;
        for (int i = 0; i < bytesRead - 3; i++, ptr++) {
            if (memcmp(ptr, signature, 4) == 0) {
                if (ptr < buffer + bytesRead) {
                    // 找到完整的标识
                    // 将标识后的剩余字节写入输出文件
                    fwrite(ptr, sizeof(unsigned char), buffer + bytesRead - ptr, outputFile);
                    found = 1;
                    break;
                }
            }
        }

        if (found == 0) {
            // 将最后3个字节移到缓冲区的开头
            memmove(buffer, ptr, 3);

            // 读取下一个块
            bytesRead = fread(buffer + 3, sizeof(char), BUF_SIZE - (sizeof(signature) - 1), inputFile);
            bytesRead += 3; // 上一个块中剩余的字节
        } else {
            break;
        }
    }

    while (!feof(inputFile)) {
        bytesRead = fread(buffer, sizeof(unsigned char), BUF_SIZE, inputFile);
        fwrite(buffer, sizeof(unsigned char), bytesRead, outputFile);
    }

    // 关闭文件
    fclose(inputFile);
    fclose(outputFile);

    return 0;
}
英文:

Solution: <br>
Input File had some extra bytes at the beginning (the first 46kb) and which came before the actual DAV header. Removing these exra bytes made for a new output DAV file that FFmpeg would then accept and correctly mux into MP4.

Future readers can look into these research points:

Process:<br>
I verified the source .dav file using hexdump -C command and found that the at the start of the file the bytes are not DHAV. It gave me a clue that the first HEVC frame is not complete.

I wrote a small C program to search whether there are further DHAV bytes in the file and I found the DHAV after about 46KB. I removed these partial bytes from the beginning of the file and wrote the remaining bytes to another file named hevc_cropped_bytes.dav and ran the following command.

ffmpeg -y -i hevc_cropped_bytes.dav -c:v copy -tag:v hvc1 hevc.mp4

This time the generated video file is properly played. Here is the program that removes the partial bytes from the beginning of the file.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#define BUF_SIZE 4096
int main()
{
FILE *inputFile, *outputFile;
char signature[] = &quot;DHAV&quot;;
unsigned char buffer[BUF_SIZE];
unsigned char *ptr;
int bytesRead;
int found = 0;
// Open the input binary file
inputFile = fopen(&quot;hevc.dav&quot;, &quot;rb&quot;);
if (inputFile == NULL) {
perror(&quot;Error opening input file&quot;);
return 1;
}
// Open the output binary file
outputFile = fopen(&quot;hevc_cropped.dav&quot;, &quot;wb&quot;);
if (outputFile == NULL) {
perror(&quot;Error creating output file&quot;);
fclose(inputFile);
return 1;
}
// Read the initial chunk
bytesRead = fread(buffer, sizeof(unsigned char), BUF_SIZE, inputFile);
while (bytesRead &gt; 0) {
ptr = buffer;
for (int i = 0; i &lt; bytesRead - 3; i++, ptr++) {
if (memcmp(ptr, signature, 4) == 0) {
if (ptr &lt; buffer + bytesRead) {
// Found the complete signature
// Write the remaining bytes after the signature to the output file
fwrite(ptr, sizeof(unsigned char), buffer + bytesRead - ptr, outputFile);
found = 1;
break;
}
}
}
if (found == 0) {
// Shift the last 3 bytes to the beginning of the buffer
memmove(buffer, ptr, 3);
// Read the next chunk
bytesRead = fread(buffer + 3, sizeof(char), BUF_SIZE - (sizeof(signature) - 1), inputFile);
bytesRead += 3; // Remaining from previous chunk
} else {
break;
}
}
while (!feof(inputFile)) {
bytesRead = fread(buffer, sizeof(unsigned char), BUF_SIZE, inputFile);
fwrite(buffer, sizeof(unsigned char), bytesRead, outputFile);
}
// Close files
fclose(inputFile);
fclose(outputFile);
return 0;
}

huangapple
  • 本文由 发表于 2023年8月5日 15:42:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76840616.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定