1
mirror of https://github.com/mpv-player/mpv synced 2024-11-11 00:15:33 +01:00
mpv/stream/stream_dvd_common.c
wm4 d191de8564 stream_dvd: better .ifo probing
stream_dvd.c includes a pseudo-protocol that recognizes .IFO files, and
plays them using libdvdread. This was relatively lazy, and could perhaps
easily trigger with files that just had the .ifo extension.

Make the checks stricter, and even probe the file header. Apparently the
first bytes in an .ifo file are always "DVDVIDEO-VTS", so check for
this.

Refuse to load the main "video_ts.ifo". The plan is to use stream_dvdnav
for it.

This also removes at least 1 memory leak.
2014-09-25 23:54:18 +02:00

166 lines
4.3 KiB
C

/*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <libavutil/intreadwrite.h>
#include "config.h"
#include <dvdread/ifo_types.h>
#ifdef __FreeBSD__
#include <sys/cdrio.h>
#endif
#ifdef __linux__
#include <linux/cdrom.h>
#include <scsi/sg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#endif
#include "osdep/io.h"
#include "common/msg.h"
#include "misc/bstr.h"
#include "stream_dvd_common.h"
const char * const dvd_audio_stream_types[8] = { "ac3","unknown","mpeg1","mpeg2ext","lpcm","unknown","dts" };
const char * const dvd_audio_stream_channels[6] = { "mono", "stereo", "unknown", "unknown", "5.1/6.1", "5.1" };
void dvd_set_speed(stream_t *stream, char *device, unsigned speed)
{
#if defined(__linux__) && defined(SG_IO) && defined(GPCMD_SET_STREAMING)
int fd;
unsigned char buffer[28];
unsigned char cmd[12];
struct sg_io_hdr sghdr;
struct stat st;
memset(&st, 0, sizeof(st));
if (stat(device, &st) == -1) return;
if (!S_ISBLK(st.st_mode)) return; /* not a block device */
switch (speed) {
case 0: /* don't touch speed setting */
return;
case -1: /* restore default value */
MP_INFO(stream, "Restoring DVD speed... ");
break;
default: /* limit to <speed> KB/s */
// speed < 100 is multiple of DVD single speed (1350KB/s)
if (speed < 100)
speed *= 1350;
MP_INFO(stream, "Limiting DVD speed to %dKB/s... ", speed);
break;
}
memset(&sghdr, 0, sizeof(sghdr));
sghdr.interface_id = 'S';
sghdr.timeout = 5000;
sghdr.dxfer_direction = SG_DXFER_TO_DEV;
sghdr.dxfer_len = sizeof(buffer);
sghdr.dxferp = buffer;
sghdr.cmd_len = sizeof(cmd);
sghdr.cmdp = cmd;
memset(cmd, 0, sizeof(cmd));
cmd[0] = GPCMD_SET_STREAMING;
cmd[10] = sizeof(buffer);
memset(buffer, 0, sizeof(buffer));
/* first sector 0, last sector 0xffffffff */
AV_WB32(buffer + 8, 0xffffffff);
if (speed == -1)
buffer[0] = 4; /* restore default */
else {
/* <speed> kilobyte */
AV_WB32(buffer + 12, speed);
AV_WB32(buffer + 20, speed);
}
/* 1 second */
AV_WB16(buffer + 18, 1000);
AV_WB16(buffer + 26, 1000);
fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (fd == -1) {
MP_INFO(stream, "Couldn't open DVD device for writing, changing DVD speed needs write access.\n");
return;
}
if (ioctl(fd, SG_IO, &sghdr) < 0)
MP_INFO(stream, "failed\n");
else
MP_INFO(stream, "successful\n");
close(fd);
#endif
}
/**
\brief Converts DVD time structure to milliseconds.
\param *dev the DVD time structure to convert
\return returns the time in milliseconds
*/
int mp_dvdtimetomsec(dvd_time_t *dt)
{
int framerates[4] = {0, 2500, 0, 2997};
int framerate = framerates[(dt->frame_u & 0xc0) >> 6];
int msec = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000;
msec += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000;
msec += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000;
if(framerate > 0)
msec += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 100000 / framerate;
return msec;
}
// Check if this is likely to be an .ifo or similar file.
int dvd_probe(const char *path, const char *ext, const char *sig)
{
if (!bstr_case_endswith(bstr0(path), bstr0(ext)))
return false;
FILE *temp = fopen(path, "rb");
if (!temp)
return false;
bool r = false;
char data[50];
assert(strlen(sig) <= sizeof(data));
if (fread(data, 50, 1, temp) == 1) {
if (memcmp(data, sig, strlen(sig)) == 0)
r = true;
}
fclose(temp);
return r;
}