Blame src/examples/bdsplice.c

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