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