iphoneffmpegmp4hevc

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


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.


Solution

  • Solution:
    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:
    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 <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;
    
        // Open the input binary file
        inputFile = fopen("hevc.dav", "rb");
        if (inputFile == NULL) {
            perror("Error opening input file");
            return 1;
        }
    
        // Open the output binary file
        outputFile = fopen("hevc_cropped.dav", "wb");
        if (outputFile == NULL) {
            perror("Error creating output file");
            fclose(inputFile);
            return 1;
        }
    
        // Read the initial chunk
        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) {
                        // 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;
    }