|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2009-2010 John Stebbins
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is free software; you can redistribute it and/or
|
|
Packit |
5e46da |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License as published by the Free Software Foundation; either
|
|
Packit |
5e46da |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
5e46da |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e46da |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
5e46da |
* Lesser General Public License for more details.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License along with this library. If not, see
|
|
Packit |
5e46da |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdio.h>
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <unistd.h>
|
|
Packit |
5e46da |
#include <libgen.h>
|
|
Packit |
5e46da |
#include <inttypes.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "bluray.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define PKT_SIZE 192
|
|
Packit |
5e46da |
#define BUF_SIZE (PKT_SIZE * 1024)
|
|
Packit |
5e46da |
#define MIN(a,b) (((a) < (b)) ? a : b)
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_usage(char *cmd)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
fprintf(stderr,
|
|
Packit |
5e46da |
"Usage: %s -t title [-c first[-last]] [-k keyfile] [-a angle] <bd path> [dest]\n"
|
|
Packit |
5e46da |
" %s -p playlist [-c first[-last]] [-k keyfile] [-a angle] <bd path> [dest]\n"
|
|
Packit |
5e46da |
"Summary:\n"
|
|
Packit |
5e46da |
" Given a title or playlist number and Blu-Ray directory tree,\n"
|
|
Packit |
5e46da |
" find the clips that compose the movie and splice\n"
|
|
Packit |
5e46da |
" them together in the destination file\n"
|
|
Packit |
5e46da |
"Options:\n"
|
|
Packit |
5e46da |
" t N - Index of title to splice. First title is 1.\n"
|
|
Packit |
5e46da |
" p N - Playlist to splice.\n"
|
|
Packit |
5e46da |
" a N - Angle. First angle is 1.\n"
|
|
Packit |
5e46da |
" c N or N-M - Chapter or chapter range. First chapter is 1.\n"
|
|
Packit |
5e46da |
" k keyfile - AACS keyfile path.\n"
|
|
Packit |
5e46da |
" <bd path> - Path to root of Blu-Ray directory tree.\n"
|
|
Packit |
5e46da |
" [dest] - Destination of spliced clips. stdout if not specified.\n"
|
|
Packit |
5e46da |
, cmd, cmd);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
exit(EXIT_FAILURE);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define OPTS "c:vt:p:k:a:"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int
|
|
Packit |
5e46da |
main(int argc, char *argv[])
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int title_no = -1;
|
|
Packit |
5e46da |
int playlist = -1;
|
|
Packit |
5e46da |
int angle = 0;
|
|
Packit |
5e46da |
char *bdpath = NULL, *dest = NULL;
|
|
Packit |
5e46da |
FILE *out;
|
|
Packit |
5e46da |
int opt;
|
|
Packit |
5e46da |
int verbose = 0;
|
|
Packit |
5e46da |
int64_t total = 0;
|
|
Packit |
5e46da |
int64_t pos, end_pos = -1;
|
|
Packit |
5e46da |
size_t size, wrote;
|
|
Packit |
5e46da |
int bytes;
|
|
Packit |
5e46da |
int title_count;
|
|
Packit |
5e46da |
BLURAY *bd;
|
|
Packit |
5e46da |
int chapter_start = 0;
|
|
Packit |
5e46da |
int chapter_end = -1;
|
|
Packit |
5e46da |
uint8_t buf[BUF_SIZE];
|
|
Packit |
5e46da |
char *keyfile = NULL;
|
|
Packit |
5e46da |
BLURAY_TITLE_INFO *ti;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
do {
|
|
Packit |
5e46da |
opt = getopt(argc, argv, OPTS);
|
|
Packit |
5e46da |
switch (opt) {
|
|
Packit |
5e46da |
case -1:
|
|
Packit |
5e46da |
if (optind < argc && bdpath == NULL) {
|
|
Packit |
5e46da |
bdpath = argv[optind];
|
|
Packit |
5e46da |
optind++;
|
|
Packit |
5e46da |
opt = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
else if (optind < argc && dest == NULL) {
|
|
Packit |
5e46da |
dest = argv[optind];
|
|
Packit |
5e46da |
optind++;
|
|
Packit |
5e46da |
opt = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 'c': {
|
|
Packit |
5e46da |
int match;
|
|
Packit |
5e46da |
match = sscanf(optarg, "%d-%d", &chapter_start, &chapter_end);
|
|
Packit |
5e46da |
if (match == 1) {
|
|
Packit |
5e46da |
chapter_end = chapter_start + 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
chapter_start--;
|
|
Packit |
5e46da |
chapter_end--;
|
|
Packit |
5e46da |
} break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 'k':
|
|
Packit |
5e46da |
keyfile = optarg;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 'a':
|
|
Packit |
5e46da |
angle = atoi(optarg);
|
|
Packit |
5e46da |
angle--;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 't':
|
|
Packit |
5e46da |
if (playlist >= 0) {
|
|
Packit |
5e46da |
_usage(argv[0]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
title_no = atoi(optarg);
|
|
Packit |
5e46da |
title_no--;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 'p':
|
|
Packit |
5e46da |
if (title_no >= 0) {
|
|
Packit |
5e46da |
_usage(argv[0]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
playlist = atoi(optarg);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 'v':
|
|
Packit |
5e46da |
verbose = 1;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
_usage(argv[0]);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} while (opt != -1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title_no < 0 && playlist < 0) {
|
|
Packit |
5e46da |
_usage(argv[0]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (optind < argc) {
|
|
Packit |
5e46da |
_usage(argv[0]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd = bd_open(bdpath, keyfile);
|
|
Packit |
5e46da |
if (bd == NULL) {
|
|
Packit |
5e46da |
fprintf(stderr, "Failed to open disc: %s\n", bdpath);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
title_count = bd_get_titles(bd, TITLES_RELEVANT, 0);
|
|
Packit |
5e46da |
if (title_count <= 0) {
|
|
Packit |
5e46da |
fprintf(stderr, "No titles found: %s\n", bdpath);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title_no >= 0) {
|
|
Packit |
5e46da |
if (!bd_select_title(bd, title_no)) {
|
|
Packit |
5e46da |
fprintf(stderr, "Failed to open title: %d\n", title_no);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
ti = bd_get_title_info(bd, title_no, angle);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
if (!bd_select_playlist(bd, playlist)) {
|
|
Packit |
5e46da |
fprintf(stderr, "Failed to open playlist: %d\n", playlist);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
ti = bd_get_playlist_info(bd, playlist, angle);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (dest) {
|
|
Packit |
5e46da |
out = fopen(dest, "wb");
|
|
Packit |
5e46da |
if (out == NULL) {
|
|
Packit |
5e46da |
fprintf(stderr, "Failed to open destination: %s\n", dest);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
out = stdout;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (angle >= (int)ti->angle_count) {
|
|
Packit |
5e46da |
fprintf(stderr, "Invalid angle %d > angle count %d. Using angle 1.\n",
|
|
Packit |
5e46da |
angle+1, ti->angle_count);
|
|
Packit |
5e46da |
angle = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bd_select_angle(bd, angle);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (chapter_start >= (int)ti->chapter_count) {
|
|
Packit |
5e46da |
fprintf(stderr, "First chapter %d > chapter count %d\n",
|
|
Packit |
5e46da |
chapter_start+1, ti->chapter_count);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (chapter_end >= (int)ti->chapter_count) {
|
|
Packit |
5e46da |
chapter_end = -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (chapter_end >= 0) {
|
|
Packit |
5e46da |
end_pos = bd_chapter_pos(bd, chapter_end);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bd_free_title_info(ti);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_seek_chapter(bd, chapter_start);
|
|
Packit |
5e46da |
pos = bd_tell(bd);
|
|
Packit |
5e46da |
while (end_pos < 0 || pos < end_pos) {
|
|
Packit |
5e46da |
size = BUF_SIZE;
|
|
Packit |
5e46da |
if (size > (size_t)(end_pos - pos)) {
|
|
Packit |
5e46da |
size = end_pos - pos;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bytes = bd_read(bd, buf, size);
|
|
Packit |
5e46da |
if (bytes <= 0) {
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pos = bd_tell(bd);
|
|
Packit |
5e46da |
wrote = fwrite(buf, 1, bytes, out);
|
|
Packit |
5e46da |
if (wrote != (size_t)bytes) {
|
|
Packit |
5e46da |
fprintf(stderr, "read/write sizes do not match: %d/%zu\n", bytes, wrote);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (wrote == 0) {
|
|
Packit |
5e46da |
if (ferror(out)) {
|
|
Packit |
5e46da |
perror("Write error");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
total += wrote;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (verbose) {
|
|
Packit |
5e46da |
fprintf(stderr, "Wrote %"PRId64" bytes\n", total);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bd_close(bd);
|
|
Packit |
5e46da |
fclose(out);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|