So, I slightly modified Windows version of thdmerge.

in theory it should prepare thd (trueHD) file for blu-ray muxing.

make file.thd and file.ac3 with ffmpeg

$ ffmpeg -i ~/vid_20210526.mp4 -vn -c:a ac3 b.ac3
$ ffmpeg -i ~/vid_20210526.mp4 -vn -c:a truehd -strict -2 a.thd

compile
gcc -o thdmerge thdmerge.cpp
run

./thdmerge a.thd b.ac3 full.thd+ac3

try to mux this resulting file with tsmuxer
#define _CRT_SECURE_NO_WARNINGS

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>

int eof(int fd)
{
    unsigned char *buffer;
    if (read(fd, buffer, 1) == 0)
	return 1;
    return 0;
}

void write_frame(unsigned char* buf, int len, int fd)
{
	int status;

	if ((status = write(fd, buf, len)) != len)
	{
		switch (errno)
		{
		case EBADF:
			perror("Bad file descriptor!");
			break;
		case ENOSPC:
			perror("No space left on device!");
			break;
		case EINVAL:
			perror("Invalid parameter: buffer was NULL!");
			break;
		default:
			break;
		}
	}
}

int next_ac3(unsigned char *buf,int ac3_fd, int out_fd)
{
	int fsize;

	if (eof(ac3_fd))
		return -1;
	// Determine the frame size to write.
	if (read(ac3_fd, buf, 8) != 8)
		return -1;
	switch (buf[4] & 0b00111110)
	{
	case 0b001000:
		fsize = 2 * 128;
		break;
	case 0b001010:
		fsize = 2 * 160;
		break;
	case 0b001100:
		fsize = 2 * 192;
		break;
	case 0b001110:
		fsize = 2 * 224;
		break;
	case 0b010000:
		fsize = 2 * 256;
		break;
	case 0b010010:
		fsize = 2 * 320;
		break;
	case 0b010100:
		fsize = 2 * 384;
		break;
	case 0b010110:
		fsize = 2 * 448;
		break;
	case 0b011000:
		fsize = 2 * 512;
		break;
	case 0b011010:
		fsize = 2 * 640;
		break;
	case 0b011100:
		fsize = 2 * 768;
		break;
	case 0b011110:
		fsize = 2 * 896;
		break;
	case 0b100000:
		fsize = 2 * 1024;
		break;
	case 0b100010:
		fsize = 2 * 1152;
		break;
	case 0b100100:
		fsize = 2 * 1280;
		break;
	default:
		return -1;
	}
	// Write the frame.
	if (lseek64(ac3_fd, -8, SEEK_CUR) == -1L)
		return -1;
	if (read(ac3_fd, buf, fsize) != fsize)
		return -1;
	write_frame(buf, fsize, out_fd);
	return 0;
}

int next_truehd(unsigned char *buf, int truehd_fd, int out_fd)
{
	int length;

	if (eof(truehd_fd))
		return -1;
	// Dtermine the frame size to write.
	if (read(truehd_fd, buf, 8) != 8)
		return -1;
	length = 2 * (((buf[0] << 8) | (buf[1])) & 0xfff);
	// Write the frame.
	if (lseek64(truehd_fd, -8, SEEK_CUR) == -1L)
		return -1;
	if (read(truehd_fd, buf, length) != length)
		return -1;
	write_frame(buf, length, out_fd);
	return 0;
}

int main(int argc, char** argv)
{
	unsigned char *buf;
	double truehd_time, ac3_time;
	int truehd_fd, ac3_fd, out_fd;
	int ac3_eof, truehd_eof;
	int truncate;

	if (argc == 1 || argc > 5)
	{
		printf("thdmerge 1.1 by Donald A. Graft\n");
		printf("Usage: thdmerge thd_file ac3_file output_file [-t]\n");
		printf("-t: truncate longer stream to length of shorter stream\n");
		exit(0);
	}
	if (argc == 5)
		truncate = 1;
	else
		truncate = 0;

	buf = (unsigned char*)malloc(1024 * 1024);
	if (buf == NULL)
	{
		printf("thdmerge: could not allocate memory\n");
		exit(1);
	}
	truehd_fd = open(argv[1],O_RDONLY);
	if (truehd_fd == -1)
	{
		printf("Cannot open TrueHD file\n");
		exit(0);
	}
	ac3_fd = open(argv[2], O_RDONLY);
	if (ac3_fd == -1)
	{
		printf("Cannot open AC3 file\n");
		exit(0);
	}
	unlink(argv[3]);
	out_fd = open(argv[3], O_WRONLY | O_CREAT , S_IREAD | S_IWRITE);
	if (out_fd == -1)
	{
		printf("Cannot open output file\n");
		exit(0);
	}

	ac3_time = truehd_time = 0;
	ac3_eof = truehd_eof = 0;
	// Interleave keeping sync.
	// Keep going until both streams hit EOF.
	while (1)
	{
		if (ac3_eof && truehd_eof)
			break;
		if (!ac3_eof && (truehd_eof || ac3_time <= truehd_time))
		{
			if (next_ac3(buf, ac3_fd, out_fd) == -1)
			{
				ac3_eof = 1;
				if (truncate)
					break;
			}
			else
				ac3_time += 0.032f;
		}
		else
		{
			if (next_truehd(buf, truehd_fd, out_fd) == -1)
			{
				truehd_eof = 1;
				if (truncate)
					break;
			}
			else
				truehd_time += 1.0f / 1200;
		}
	}

	free(buf);
	close(truehd_fd);
	close(ac3_fd);
	close(out_fd);
	return 0;
}
-- 
Cin mailing list
[email protected]
https://lists.cinelerra-gg.org/mailman/listinfo/cin

Reply via email to