mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-31 09:21:18 +02:00
Merge remote-tracking branch 'check/cst-next'
This commit is contained in:
@@ -31,6 +31,7 @@ libneutrino_driver_a_SOURCES = \
|
||||
fontrenderer.cpp \
|
||||
framebuffer_ng.cpp \
|
||||
genpsi.cpp \
|
||||
moviecut.cpp \
|
||||
neutrinofonts.cpp \
|
||||
radiotext.cpp \
|
||||
radiotools.cpp \
|
||||
|
643
src/driver/moviecut.cpp
Normal file
643
src/driver/moviecut.cpp
Normal file
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
Copyright (C) 2015 CoolStream International Ltd
|
||||
|
||||
License: GPLv2
|
||||
|
||||
This program 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;
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include <global.h>
|
||||
#include <neutrino.h>
|
||||
#include <gui/widget/hintbox.h>
|
||||
#include <gui/widget/helpbox.h>
|
||||
#include <gui/widget/icons.h>
|
||||
#include <gui/widget/messagebox.h>
|
||||
#include <gui/components/cc.h>
|
||||
|
||||
#include <driver/screen_max.h>
|
||||
#include <driver/moviecut.h>
|
||||
|
||||
#define PSI_SIZE 188*2
|
||||
#define BUF_SIZE 1395*188
|
||||
#define SAFE_GOP 1395*188
|
||||
#define MP_TS_SIZE 262072 // ~0.5 sec
|
||||
#define MINUTEOFFSET 117*262072
|
||||
#define SECONDOFFSET MP_TS_SIZE*2
|
||||
|
||||
typedef struct pvr_file_info
|
||||
{
|
||||
uint32_t uDuration; /* Time duration in Ms */
|
||||
uint32_t uTSPacketSize;
|
||||
} PVR_FILE_INFO;
|
||||
|
||||
struct mybook {
|
||||
off64_t pos;
|
||||
off64_t len;
|
||||
bool ok;
|
||||
};
|
||||
|
||||
CMovieCut::CMovieCut()
|
||||
{
|
||||
frameBuffer = CFrameBuffer::getInstance();
|
||||
timescale = NULL;
|
||||
percent = 0;
|
||||
int dx = 256;
|
||||
x = (((g_settings.screen_EndX- g_settings.screen_StartX)- dx) / 2) + g_settings.screen_StartX;
|
||||
y = g_settings.screen_EndY - 50;
|
||||
}
|
||||
|
||||
CMovieCut::~CMovieCut()
|
||||
{
|
||||
delete timescale;
|
||||
}
|
||||
|
||||
void CMovieCut::paintProgress(bool refresh)
|
||||
{
|
||||
if (!timescale) {
|
||||
timescale = new CProgressBar();
|
||||
timescale->setType(CProgressBar::PB_TIMESCALE);
|
||||
}
|
||||
if (refresh) {
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0);//TODO: remove unneeded box paints
|
||||
timescale->reset();
|
||||
}
|
||||
timescale->setProgress(x + 41, y + 12, 200, 15, percent, 100);
|
||||
timescale->paint();
|
||||
}
|
||||
|
||||
void CMovieCut::reset_atime(const char * path, time_t tt)
|
||||
{
|
||||
struct utimbuf ut;
|
||||
ut.actime = tt-1;
|
||||
ut.modtime = tt-1;
|
||||
utime(path, &ut);
|
||||
}
|
||||
|
||||
void CMovieCut::WriteHeader(const char * path, uint32_t duration)
|
||||
{
|
||||
int srcfd = open(path, O_WRONLY | O_LARGEFILE);
|
||||
if (srcfd >= 0) {
|
||||
if (lseek64(srcfd, 188-sizeof(PVR_FILE_INFO), SEEK_SET) >= 0) {
|
||||
PVR_FILE_INFO pinfo;
|
||||
pinfo.uDuration = duration;
|
||||
pinfo.uTSPacketSize = 188;
|
||||
write(srcfd, (uint8_t *)&pinfo, sizeof(PVR_FILE_INFO));
|
||||
}
|
||||
close(srcfd);
|
||||
} else
|
||||
perror(path);
|
||||
}
|
||||
|
||||
uint32_t CMovieCut::getHeaderDurationMS(MI_MOVIE_INFO * minfo)
|
||||
{
|
||||
uint32_t duration = 0;
|
||||
int srcfd = open(minfo->file.Name.c_str(), O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd >= 0) {
|
||||
if (lseek64(srcfd, 188-sizeof(PVR_FILE_INFO), SEEK_SET) >= 0) {
|
||||
PVR_FILE_INFO pinfo;
|
||||
memset(&pinfo, 0, sizeof(PVR_FILE_INFO));
|
||||
read(srcfd, (uint8_t *)&pinfo, sizeof(PVR_FILE_INFO));
|
||||
if (pinfo.uTSPacketSize == 188)
|
||||
duration = pinfo.uDuration;
|
||||
close(srcfd);
|
||||
printf("CMovieCut::%s: [%s] duration %d ms\n", __func__, minfo->file.Name.c_str(), duration);
|
||||
}
|
||||
} else
|
||||
perror(minfo->file.Name.c_str());
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
off64_t CMovieCut::getSecondSize(MI_MOVIE_INFO * minfo)
|
||||
{
|
||||
struct stat64 s;
|
||||
if (stat64(minfo->file.Name.c_str(), &s)) {
|
||||
perror(minfo->file.Name.c_str());
|
||||
return 0;
|
||||
}
|
||||
uint32_t duration = getHeaderDurationMS(minfo);
|
||||
|
||||
int len = minfo->length;
|
||||
if (len <= 0)
|
||||
len = 1;
|
||||
|
||||
if (duration == 0)
|
||||
duration = len * 60 * 1000;
|
||||
|
||||
off64_t mssize = ((float)s.st_size / (float)duration);
|
||||
printf("CMovieCut::%s: [%s] bytes per second: %lld\n", __func__, minfo->file.Name.c_str(), mssize*1000);
|
||||
return mssize*1000;
|
||||
}
|
||||
|
||||
bool CMovieCut::truncateMovie(MI_MOVIE_INFO * minfo)
|
||||
{
|
||||
off64_t secsize = getSecondSize(minfo);
|
||||
if (minfo->bookmarks.end == 0 || secsize == 0)
|
||||
return false;
|
||||
|
||||
off64_t newsize = secsize * minfo->bookmarks.end;
|
||||
|
||||
printf("CMovieCut::%s: [%s] truncate to %d sec, new size %lld\n", __func__, minfo->file.Name.c_str(), minfo->bookmarks.end, newsize);
|
||||
if (truncate(minfo->file.Name.c_str(), newsize)) {
|
||||
perror(minfo->file.Name.c_str());
|
||||
return false;
|
||||
}
|
||||
minfo->file.Size = newsize;
|
||||
minfo->length = minfo->bookmarks.end/60;
|
||||
minfo->bookmarks.end = 0;
|
||||
reset_atime(minfo->file.Name.c_str(), minfo->file.Time);
|
||||
return true;
|
||||
}
|
||||
|
||||
int CMovieCut::check_pes_start (unsigned char *packet)
|
||||
{
|
||||
// PCKT: 47 41 91 37 07 50 3F 14 BF 04 FE B9 00 00 01 EA 00 00 8C ...
|
||||
if (packet[0] == 0x47 && // sync byte 0x47
|
||||
(packet[1] & 0x40)) // pusi == 1
|
||||
{
|
||||
/* good, now we have to check if it is video stream */
|
||||
unsigned char *pes = packet + 4;
|
||||
if (packet[3] & 0x20) // adaptation field is present
|
||||
pes += packet[4] + 1;
|
||||
|
||||
if (!memcmp(pes, "\x00\x00\x01", 3) && (pes[3] & 0xF0) == 0xE0) // PES start & video type
|
||||
{
|
||||
pes += 4;
|
||||
while (pes < (packet + 188 - 4))
|
||||
if (!memcmp(pes, "\x00\x00\x01\xB8", 4)) // GOP detect
|
||||
return 1;
|
||||
else
|
||||
pes++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CMovieCut::find_gop(unsigned char *buf, int r)
|
||||
{
|
||||
for (int j = 0; j < r/188; j++) {
|
||||
if (check_pes_start(&buf[188*j]))
|
||||
return 188*j;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
off64_t CMovieCut::fake_read(int fd, unsigned char *buf, size_t size, off64_t fsize)
|
||||
{
|
||||
off64_t cur = lseek64(fd, 0, SEEK_CUR);
|
||||
|
||||
buf[0] = 0x47;
|
||||
if((cur + size) > fsize)
|
||||
return(fsize - cur);
|
||||
else
|
||||
return size;
|
||||
}
|
||||
|
||||
int CMovieCut::read_psi(const char * spart, unsigned char * buf)
|
||||
{
|
||||
int srcfd = open(spart, O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd >= 0) {
|
||||
/* read psi */
|
||||
int r = read(srcfd, buf, PSI_SIZE);
|
||||
close(srcfd);
|
||||
if (r != PSI_SIZE) {
|
||||
perror("read psi");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CMovieCut::save_info(CMovieInfo * cmovie, MI_MOVIE_INFO * minfo, char * dpart, off64_t spos, off64_t secsize)
|
||||
{
|
||||
MI_MOVIE_INFO ninfo = *minfo;
|
||||
ninfo.file.Name = dpart;
|
||||
ninfo.file.Size = spos;
|
||||
ninfo.length = spos/secsize/60;
|
||||
ninfo.bookmarks.end = 0;
|
||||
ninfo.bookmarks.start = 0;
|
||||
ninfo.bookmarks.lastPlayStop = 0;
|
||||
for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) {
|
||||
if (ninfo.bookmarks.user[book_nr].pos != 0 && ninfo.bookmarks.user[book_nr].length > 0) {
|
||||
ninfo.bookmarks.user[book_nr].pos = 0;
|
||||
ninfo.bookmarks.user[book_nr].length = 0;
|
||||
}
|
||||
}
|
||||
cmovie->saveMovieInfo(ninfo);
|
||||
WriteHeader(ninfo.file.Name.c_str(), spos/secsize*1000);
|
||||
reset_atime(dpart, minfo->file.Time);
|
||||
}
|
||||
|
||||
void CMovieCut::findNewName(const char * fname, char * dpart, size_t dpart_len)
|
||||
{
|
||||
char npart[255];
|
||||
snprintf(npart, sizeof(npart), "%s", fname);
|
||||
char * ptr = strstr(npart+strlen(npart)-3, ".ts");
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
|
||||
struct stat64 s;
|
||||
int dp = 0;
|
||||
snprintf(dpart, dpart_len, "%s_%d.ts", npart, dp);
|
||||
while (!stat64(dpart, &s))
|
||||
snprintf(dpart, dpart_len, "%s_%d.ts", npart, ++dp);
|
||||
}
|
||||
|
||||
int CMovieCut::compare_book(const void *x, const void *y)
|
||||
{
|
||||
struct mybook *px = (struct mybook*) x;
|
||||
struct mybook *py = (struct mybook*) y;
|
||||
int dx = px->pos / (off64_t) 1024;
|
||||
int dy = py->pos / (off64_t) 1024;
|
||||
int res = dx - dy;
|
||||
//printf("SORT: %lld and %lld res %d\n", px->pos, py->pos, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int CMovieCut::getInput()
|
||||
{
|
||||
neutrino_msg_data_t data;
|
||||
neutrino_msg_t msg;
|
||||
int retval = 0;
|
||||
g_RCInput->getMsg(&msg, &data, 1, false);
|
||||
if (msg == CRCInput::RC_home) {
|
||||
if (ShowMsg(LOCALE_MESSAGEBOX_INFO, "Cancel movie cut/split ?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes)
|
||||
retval |= 4;
|
||||
}
|
||||
if (msg != CRCInput::RC_timeout)
|
||||
retval |= 1;
|
||||
if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all)
|
||||
retval |= 2;
|
||||
//printf("input: msg %d (%x) ret %d\n", msg, msg, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CMovieCut::cutMovie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie)
|
||||
{
|
||||
struct mybook books[MI_MOVIE_BOOK_USER_MAX+2];
|
||||
unsigned char psi[PSI_SIZE];
|
||||
char dpart[255];
|
||||
int bcount = 0;
|
||||
int dstfd = -1, srcfd = -1;
|
||||
struct stat64 s;
|
||||
off64_t spos = 0;
|
||||
bool need_gop = 0;
|
||||
int was_cancel = 0;
|
||||
bool retval = false;
|
||||
time_t tt = time(0);
|
||||
time_t tt1;
|
||||
|
||||
unsigned char * buf = new unsigned char[BUF_SIZE];
|
||||
if (buf == 0) {
|
||||
perror("new");
|
||||
return false;
|
||||
}
|
||||
|
||||
paintProgress(true);
|
||||
|
||||
off64_t size = minfo->file.Size;
|
||||
off64_t secsize = getSecondSize(minfo);
|
||||
off64_t newsize = size;
|
||||
|
||||
if (minfo->bookmarks.start != 0) {
|
||||
books[bcount].pos = 0;
|
||||
books[bcount].len = (minfo->bookmarks.start * secsize)/188 * 188;
|
||||
if (books[bcount].len > SAFE_GOP)
|
||||
books[bcount].len -= SAFE_GOP;
|
||||
books[bcount].ok = 1;
|
||||
printf("CMovieCut::%s: start bookmark %d at %" PRId64 " len %" PRId64 "\n", __func__, bcount, books[bcount].pos, books[bcount].len);
|
||||
bcount++;
|
||||
}
|
||||
for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) {
|
||||
if (minfo->bookmarks.user[book_nr].pos != 0 && minfo->bookmarks.user[book_nr].length > 0) {
|
||||
books[bcount].pos = (minfo->bookmarks.user[book_nr].pos * secsize)/188 * 188;
|
||||
books[bcount].len = (minfo->bookmarks.user[book_nr].length * secsize)/188 * 188;
|
||||
if (books[bcount].len > SAFE_GOP)
|
||||
books[bcount].len -= SAFE_GOP;
|
||||
books[bcount].ok = 1;
|
||||
printf("CMovieCut::%s: jump bookmark %d at %" PRId64 " len %" PRId64 " -> skip to %" PRId64 "\n", __func__, bcount, books[bcount].pos, books[bcount].len, books[bcount].pos+books[bcount].len);
|
||||
bcount++;
|
||||
}
|
||||
}
|
||||
if (minfo->bookmarks.end != 0) {
|
||||
books[bcount].pos = ((off64_t) minfo->bookmarks.end * secsize)/188 * 188;
|
||||
books[bcount].len = size - books[bcount].pos;
|
||||
books[bcount].ok = 1;
|
||||
printf("CMovieCut::%s: end bookmark %d at %" PRId64 "\n", __func__, bcount, books[bcount].pos);
|
||||
bcount++;
|
||||
}
|
||||
printf("\n");
|
||||
if (!bcount) {
|
||||
delete [] buf;
|
||||
return false;
|
||||
}
|
||||
qsort(books, bcount, sizeof(struct mybook), compare_book);
|
||||
for (int i = 0; i < bcount; i++) {
|
||||
if (books[i].ok) {
|
||||
//printf("cut: bookmark %d at %" PRId64 " len %" PRId64 " -> skip to %" PRId64 "\n", i, books[i].pos, books[i].len, books[i].pos+books[i].len);
|
||||
newsize -= books[i].len;
|
||||
off64_t curend = books[i].pos + books[i].len;
|
||||
/* check for overlapping bookmarks */
|
||||
for (int j = i + 1; j < bcount; j++) {
|
||||
if ((books[j].pos > books[i].pos) && (books[j].pos < curend)) {
|
||||
off64_t newend = books[j].pos + books[j].len;
|
||||
if (newend > curend) {
|
||||
printf("CMovieCut::%s: bad bookmark %d, position %" PRId64 " len %" PRId64 ", adjusting..\n", __func__, j, books[j].pos, books[j].len);
|
||||
books[j].pos = curend;
|
||||
books[j].len = newend - curend;
|
||||
} else {
|
||||
printf("CMovieCut::%s: bad bookmark %d, position %" PRId64 " len %" PRId64 ", skipping..\n", __func__, j, books[j].pos, books[j].len);
|
||||
books[j].ok = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
findNewName(minfo->file.Name.c_str(), dpart, sizeof(dpart));
|
||||
|
||||
int bindex = 0;
|
||||
off64_t bpos = books[bindex].pos;
|
||||
off64_t bskip = books[bindex].len;
|
||||
off64_t offset = 0;
|
||||
|
||||
printf("CMovieCut::%s: new file %s, expected size %" PRId64 ", start time %s", __func__, dpart, newsize, ctime(&tt));
|
||||
dstfd = open(dpart, O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE, 0644);
|
||||
if (dstfd < 0) {
|
||||
perror(dpart);
|
||||
goto ret_err;
|
||||
}
|
||||
if (read_psi(minfo->file.Name.c_str(), &psi[0])) {
|
||||
perror(minfo->file.Name.c_str());
|
||||
goto ret_err;
|
||||
}
|
||||
write(dstfd, psi, PSI_SIZE);
|
||||
|
||||
stat64(minfo->file.Name.c_str(), &s);
|
||||
|
||||
srcfd = open(minfo->file.Name.c_str(), O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd < 0) {
|
||||
perror(minfo->file.Name.c_str());
|
||||
goto ret_err;
|
||||
}
|
||||
lseek64(srcfd, offset, SEEK_SET);
|
||||
|
||||
/* process all bookmarks */
|
||||
while (true) {
|
||||
off64_t until = bpos;
|
||||
printf("CMovieCut::%s: bookmark #%d reading from %" PRId64 " to %" PRId64 " (%" PRId64 ") want gop %d\n", __func__, bindex, offset, until, until - offset, need_gop);
|
||||
/* read up to jump end */
|
||||
while (offset < until) {
|
||||
int msg = getInput();
|
||||
was_cancel = msg & 2;
|
||||
if (msg & 4) {
|
||||
unlink(dpart);
|
||||
retval = true;
|
||||
goto ret_err;
|
||||
}
|
||||
size_t toread = (until-offset) > BUF_SIZE ? BUF_SIZE : until - offset;
|
||||
size_t r = read(srcfd, buf, toread);
|
||||
if (r > 0) {
|
||||
int wptr = 0;
|
||||
if (r != toread)
|
||||
printf("CMovieCut::%s: short read at %" PRId64 ": %d\n", __func__, offset, r);
|
||||
if (buf[0] != 0x47)
|
||||
printf("CMovieCut::%s: buffer not aligned at %" PRId64 "\n", __func__, offset);
|
||||
if (need_gop) {
|
||||
int gop = find_gop(buf, r);
|
||||
if (gop >= 0) {
|
||||
printf("CMovieCut::%s: GOP found at %" PRId64 " offset %d\n", __func__, (off64_t)(offset+gop), gop);
|
||||
newsize -= gop;
|
||||
wptr = gop;
|
||||
} else
|
||||
printf("CMovieCut::%s: GOP not found\n", __func__);
|
||||
need_gop = 0;
|
||||
}
|
||||
offset += r;
|
||||
spos += r - wptr;
|
||||
percent = (int) ((float)(spos)/(float)(newsize)*100.);
|
||||
paintProgress(msg != 0);
|
||||
size_t wr = write(dstfd, &buf[wptr], r-wptr);
|
||||
if (wr < (r-wptr)) {
|
||||
perror(dpart);
|
||||
goto ret_err;
|
||||
}
|
||||
} else if (offset < s.st_size) {
|
||||
/* read error ? */
|
||||
perror(minfo->file.Name.c_str());
|
||||
goto ret_err;
|
||||
}
|
||||
}
|
||||
printf("CMovieCut::%s: current file pos %" PRId64 " write pos %" PRId64 " book pos %" PRId64 " next offset %" PRId64 "\n", __func__, offset, spos, bpos, bpos + bskip);
|
||||
need_gop = 1;
|
||||
offset = bpos + bskip;
|
||||
|
||||
bindex++;
|
||||
while(bindex < bcount) {
|
||||
if(books[bindex].ok)
|
||||
break;
|
||||
else
|
||||
bindex++;
|
||||
}
|
||||
if(bindex < bcount) {
|
||||
bpos = books[bindex].pos;
|
||||
bskip = books[bindex].len;
|
||||
} else
|
||||
bpos = size;
|
||||
|
||||
if (offset >= s.st_size) {
|
||||
printf("CMovieCut::%s: offset behind EOF: %" PRId64 " from %" PRId64 "\n", __func__, offset, s.st_size);
|
||||
break;
|
||||
}
|
||||
lseek64(srcfd, offset, SEEK_SET);
|
||||
}
|
||||
tt1 = time(0);
|
||||
printf("CMovieCut::%s: total written %" PRId64 " tooks %ld secs end time %s", __func__, spos, tt1-tt, ctime(&tt1));
|
||||
|
||||
save_info(cmovie, minfo, dpart, spos, secsize);
|
||||
retval = true;
|
||||
ret_err:
|
||||
if (srcfd >= 0)
|
||||
close(srcfd);
|
||||
if (dstfd >= 0)
|
||||
close(dstfd);
|
||||
|
||||
delete [] buf;
|
||||
if (was_cancel)
|
||||
g_RCInput->postMsg(CRCInput::RC_home, 0);
|
||||
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0);//TODO: remove unneeded box paints
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CMovieCut::copyMovie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie, bool onefile)
|
||||
{
|
||||
struct mybook books[MI_MOVIE_BOOK_USER_MAX+2];
|
||||
struct stat64 s;
|
||||
char dpart[255];
|
||||
unsigned char psi[PSI_SIZE];
|
||||
int dstfd = -1, srcfd = -1;
|
||||
off64_t spos = 0, btotal = 0;
|
||||
time_t tt = time(0);
|
||||
bool need_gop = 0;
|
||||
bool dst_done = 0;
|
||||
bool was_cancel = false;
|
||||
bool retval = false;
|
||||
int bcount = 0;
|
||||
off64_t newsize = 0;
|
||||
|
||||
off64_t secsize = getSecondSize(minfo);
|
||||
for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) {
|
||||
if (minfo->bookmarks.user[book_nr].pos != 0 && minfo->bookmarks.user[book_nr].length > 0) {
|
||||
books[bcount].pos = (minfo->bookmarks.user[book_nr].pos * secsize)/188 * 188;
|
||||
if (books[bcount].pos > SAFE_GOP)
|
||||
books[bcount].pos -= SAFE_GOP;
|
||||
books[bcount].len = (minfo->bookmarks.user[book_nr].length * secsize)/188 * 188;
|
||||
books[bcount].ok = 1;
|
||||
printf("copy: jump bookmark %d at %" PRId64 " len %" PRId64 "\n", bcount, books[bcount].pos, books[bcount].len);
|
||||
newsize += books[bcount].len;
|
||||
bcount++;
|
||||
}
|
||||
}
|
||||
if (!bcount)
|
||||
return false;
|
||||
|
||||
unsigned char * buf = new unsigned char[BUF_SIZE];
|
||||
if (buf == 0) {
|
||||
perror("new");
|
||||
return false;
|
||||
}
|
||||
|
||||
paintProgress(true);
|
||||
|
||||
printf("********* %d boormarks, to %s file(s), expected size to copy %" PRId64 ", start time %s", bcount, onefile ? "one" : "many", newsize, ctime(&tt));
|
||||
if (read_psi(minfo->file.Name.c_str(), &psi[0])) {
|
||||
perror(minfo->file.Name.c_str());
|
||||
goto ret_err;
|
||||
}
|
||||
srcfd = open(minfo->file.Name.c_str(), O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd < 0) {
|
||||
perror(minfo->file.Name.c_str());
|
||||
goto ret_err;
|
||||
}
|
||||
stat64(minfo->file.Name.c_str(), &s);
|
||||
for (int i = 0; i < bcount; i++) {
|
||||
printf("\ncopy: processing bookmark %d at %" PRId64 " len %" PRId64 "\n", i, books[i].pos, books[i].len);
|
||||
|
||||
if (!dst_done || !onefile) {
|
||||
findNewName(minfo->file.Name.c_str(), dpart, sizeof(dpart));
|
||||
dstfd = open(dpart, O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE, 0644);
|
||||
printf("copy: new file %s fd %d\n", dpart, dstfd);
|
||||
if (dstfd < 0) {
|
||||
printf("failed to open %s\n", dpart);
|
||||
goto ret_err;
|
||||
}
|
||||
dst_done = 1;
|
||||
spos = 0;
|
||||
write(dstfd, psi, PSI_SIZE);
|
||||
}
|
||||
need_gop = 1;
|
||||
|
||||
off64_t offset = books[i].pos;
|
||||
lseek64(srcfd, offset, SEEK_SET);
|
||||
off64_t until = books[i].pos + books[i].len;
|
||||
printf("copy: read from %" PRId64 " to %" PRId64 " read size %d want gop %d\n", offset, until, BUF_SIZE, need_gop);
|
||||
while (offset < until) {
|
||||
size_t toread = (until-offset) > BUF_SIZE ? BUF_SIZE : until - offset;
|
||||
int msg = getInput();
|
||||
was_cancel = msg & 2;
|
||||
if (msg & 4) {
|
||||
unlink(dpart);
|
||||
retval = true;
|
||||
goto ret_err;
|
||||
}
|
||||
size_t r = read(srcfd, buf, toread);
|
||||
if (r > 0) {
|
||||
int wptr = 0;
|
||||
if (r != toread)
|
||||
printf("****** short read ? %d\n", r);
|
||||
if (buf[0] != 0x47)
|
||||
printf("copy: buffer not aligned at %" PRId64 "\n", offset);
|
||||
if (need_gop) {
|
||||
int gop = find_gop(buf, r);
|
||||
if (gop >= 0) {
|
||||
printf("cut: GOP found at %" PRId64 " offset %d\n", (off64_t)(offset+gop), gop);
|
||||
newsize -= gop;
|
||||
wptr = gop;
|
||||
} else
|
||||
printf("cut: GOP needed, but not found\n");
|
||||
need_gop = 0;
|
||||
}
|
||||
offset += r;
|
||||
spos += r - wptr;
|
||||
btotal += r;
|
||||
percent = (int) ((float)(btotal)/(float)(newsize)*100.);
|
||||
paintProgress(msg != 0);
|
||||
|
||||
size_t wr = write(dstfd, &buf[wptr], r-wptr);
|
||||
if (wr < (r-wptr)) {
|
||||
printf("write to %s failed\n", dpart);
|
||||
unlink(dpart);
|
||||
goto ret_err;
|
||||
}
|
||||
} else if (offset < s.st_size) {
|
||||
/* read error ? */
|
||||
perror(minfo->file.Name.c_str());
|
||||
break;
|
||||
}
|
||||
} /* while(offset < until) */
|
||||
|
||||
if (!onefile) {
|
||||
close(dstfd);
|
||||
dstfd = -1;
|
||||
save_info(cmovie, minfo, dpart, spos, secsize);
|
||||
time_t tt1 = time(0);
|
||||
printf("copy: ********* %s: total written %" PRId64 " took %ld secs\n", dpart, spos, tt1-tt);
|
||||
}
|
||||
} /* for all books */
|
||||
if (onefile) {
|
||||
save_info(cmovie, minfo, dpart, spos, secsize);
|
||||
time_t tt1 = time(0);
|
||||
printf("copy: ********* %s: total written %" PRId64 " took %ld secs\n", dpart, spos, tt1-tt);
|
||||
}
|
||||
retval = true;
|
||||
ret_err:
|
||||
if (srcfd >= 0)
|
||||
close(srcfd);
|
||||
if (dstfd >= 0)
|
||||
close(dstfd);
|
||||
delete [] buf;
|
||||
if (was_cancel)
|
||||
g_RCInput->postMsg(CRCInput::RC_home, 0);
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0);//TODO: remove unneeded box paints
|
||||
return retval;
|
||||
}
|
60
src/driver/moviecut.h
Normal file
60
src/driver/moviecut.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright (C) 2015 CoolStream International Ltd
|
||||
|
||||
License: GPLv2
|
||||
|
||||
This program 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;
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MOVIE_CUT__
|
||||
#define __MOVIE_CUT__
|
||||
|
||||
#include <gui/movieinfo.h>
|
||||
#include <gui/components/cc.h>
|
||||
#include <driver/framebuffer.h>
|
||||
|
||||
class CMovieCut
|
||||
{
|
||||
private:
|
||||
CProgressBar *timescale;
|
||||
CFrameBuffer * frameBuffer;
|
||||
int x;
|
||||
int y;
|
||||
int percent;
|
||||
|
||||
void reset_atime(const char * path, time_t tt);
|
||||
uint32_t getHeaderDurationMS(MI_MOVIE_INFO * minfo);
|
||||
off64_t getSecondSize(MI_MOVIE_INFO * minfo);
|
||||
void WriteHeader(const char * path, uint32_t duration);
|
||||
int check_pes_start (unsigned char *packet);
|
||||
int find_gop(unsigned char *buf, int r);
|
||||
off64_t fake_read(int fd, unsigned char *buf, size_t size, off64_t fsize);
|
||||
int read_psi(const char * spart, unsigned char * buf);
|
||||
void save_info(CMovieInfo * cmovie, MI_MOVIE_INFO * minfo, char * dpart, off64_t spos, off64_t secsize);
|
||||
void findNewName(const char * fname, char * dpart,size_t dpart_len);
|
||||
static int compare_book(const void *x, const void *y);
|
||||
int getInput();
|
||||
|
||||
void paintProgress(bool refresh);
|
||||
|
||||
public:
|
||||
CMovieCut();
|
||||
~CMovieCut();
|
||||
bool truncateMovie(MI_MOVIE_INFO * minfo);
|
||||
bool cutMovie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie);
|
||||
bool copyMovie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie, bool onefile);
|
||||
//int handleMsg(const neutrino_msg_t _msg, neutrino_msg_data_t data);
|
||||
};
|
||||
|
||||
#endif
|
@@ -68,23 +68,18 @@
|
||||
#include <system/helpers.h>
|
||||
#include <system/ytcache.h>
|
||||
#include <zapit/debug.h>
|
||||
#include <driver/moviecut.h>
|
||||
|
||||
#include <timerdclient/timerdclient.h>
|
||||
#include <system/hddstat.h>
|
||||
|
||||
extern CPictureViewer * g_PicViewer;
|
||||
static CProgressBar *timescale;
|
||||
|
||||
#define my_scandir scandir64
|
||||
#define my_alphasort alphasort64
|
||||
typedef struct stat64 stat_struct;
|
||||
typedef struct dirent64 dirent_struct;
|
||||
#define my_stat stat64
|
||||
//static off64_t truncate_movie(char * name, off64_t size, int len, int seconds);
|
||||
static off64_t truncate_movie(MI_MOVIE_INFO * minfo);
|
||||
static off64_t cut_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie);
|
||||
static off64_t copy_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie, bool onefile);
|
||||
|
||||
#define TRACE printf
|
||||
|
||||
#define NUMBER_OF_MOVIES_LAST 40 // This is the number of movies shown in last recored and last played list
|
||||
@@ -1770,7 +1765,8 @@ bool CMovieBrowser::onButtonPressMainFrame(neutrino_msg_t msg)
|
||||
hintBox->hide();
|
||||
delete hintBox;
|
||||
framebuffer->paintBackground(); // clear screen
|
||||
off64_t res = copy_movie(m_movieSelectionHandler, &m_movieInfo, msg == CRCInput::RC_radio);
|
||||
CMovieCut mc;
|
||||
bool res = mc.copyMovie(m_movieSelectionHandler, &m_movieInfo, msg == CRCInput::RC_radio);
|
||||
//g_RCInput->clearRCMsg();
|
||||
if (res == 0)
|
||||
ShowMsg(LOCALE_MESSAGEBOX_ERROR, LOCALE_MOVIEBROWSER_COPY_FAILED, CMessageBox::mbrCancel, CMessageBox::mbCancel, NEUTRINO_ICON_ERROR);
|
||||
@@ -1793,13 +1789,14 @@ bool CMovieBrowser::onButtonPressMainFrame(neutrino_msg_t msg)
|
||||
hintBox->hide();
|
||||
delete hintBox;
|
||||
framebuffer->paintBackground(); // clear screen
|
||||
off64_t res = cut_movie(m_movieSelectionHandler, &m_movieInfo);
|
||||
CMovieCut mc;
|
||||
bool res = mc.cutMovie(m_movieSelectionHandler, &m_movieInfo);
|
||||
//g_RCInput->clearRCMsg();
|
||||
if (res == 0)
|
||||
if (!res)
|
||||
ShowMsg(LOCALE_MESSAGEBOX_ERROR, LOCALE_MOVIEBROWSER_CUT_FAILED, CMessageBox::mbrCancel, CMessageBox::mbCancel, NEUTRINO_ICON_ERROR);
|
||||
else {
|
||||
else
|
||||
loadMovies();
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
@@ -1813,11 +1810,13 @@ bool CMovieBrowser::onButtonPressMainFrame(neutrino_msg_t msg)
|
||||
if (ShowMsg(LOCALE_MESSAGEBOX_INFO, LOCALE_MOVIEBROWSER_TRUNCATE, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) {
|
||||
CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, LOCALE_MOVIEBROWSER_TRUNCATING);
|
||||
hintBox->paint();
|
||||
off64_t res = truncate_movie(m_movieSelectionHandler);
|
||||
|
||||
CMovieCut mc;
|
||||
bool res = mc.truncateMovie(m_movieSelectionHandler);
|
||||
hintBox->hide();
|
||||
delete hintBox;
|
||||
g_RCInput->clearRCMsg();
|
||||
if (res == 0)
|
||||
if (!res)
|
||||
ShowMsg(LOCALE_MESSAGEBOX_ERROR, LOCALE_MOVIEBROWSER_TRUNCATE_FAILED, CMessageBox::mbrCancel, CMessageBox::mbCancel, NEUTRINO_ICON_ERROR);
|
||||
else {
|
||||
//printf("New movie info: size %lld len %d\n", res, m_movieSelectionHandler->bookmarks.end/60);
|
||||
@@ -2967,10 +2966,12 @@ int CMovieBrowser::showStartPosSelectionMenu(void) // P2
|
||||
startPosSelectionMenu.addIntroItems(LOCALE_MOVIEBROWSER_START_HEAD, NONEXISTANT_LOCALE, CMenuWidget::BTN_TYPE_CANCEL);
|
||||
|
||||
int off = startPosSelectionMenu.getItemsCount();
|
||||
bool got_start_pos = false;
|
||||
|
||||
if (m_movieSelectionHandler->bookmarks.start != 0)
|
||||
{
|
||||
startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, true, start_pos));
|
||||
got_start_pos = true;
|
||||
startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, true, start_pos), true);
|
||||
position[menu_nr++] = m_movieSelectionHandler->bookmarks.start;
|
||||
}
|
||||
if (m_movieSelectionHandler->bookmarks.lastPlayStop != 0)
|
||||
@@ -2979,7 +2980,7 @@ int CMovieBrowser::showStartPosSelectionMenu(void) // P2
|
||||
position[menu_nr++] = m_movieSelectionHandler->bookmarks.lastPlayStop;
|
||||
}
|
||||
|
||||
startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_START_RECORD_START, true,NULL), true);
|
||||
startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_START_RECORD_START, true,NULL), got_start_pos ? false : true);
|
||||
position[menu_nr++] = 0;
|
||||
|
||||
for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX && menu_nr < MAX_NUMBER_OF_BOOKMARK_ITEMS; i++)
|
||||
@@ -3889,669 +3890,3 @@ int CDirMenu::show(void)
|
||||
int ret = dirMenu.exec(NULL," ");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void reset_atime(char * path, time_t tt)
|
||||
{
|
||||
struct utimbuf ut;
|
||||
ut.actime = tt-1;
|
||||
ut.modtime = tt-1;
|
||||
utime(path, &ut);
|
||||
}
|
||||
|
||||
#define BUF_SIZE 1395*188
|
||||
#define SAFE_GOP 1395*188
|
||||
#define MP_TS_SIZE 262072 // ~0.5 sec
|
||||
#define MINUTEOFFSET 117*262072
|
||||
#define SECONDOFFSET MP_TS_SIZE*2
|
||||
static off64_t truncate_movie(MI_MOVIE_INFO * minfo)
|
||||
{
|
||||
struct stat64 s;
|
||||
char spart[255];
|
||||
int part = 0, tpart = 0;
|
||||
bool found = 0;
|
||||
const char *name = minfo->file.Name.c_str();
|
||||
off64_t size = minfo->file.Size;
|
||||
int len = minfo->length;
|
||||
int seconds = minfo->bookmarks.end;
|
||||
off64_t minuteoffset = len ? size / len : MINUTEOFFSET;
|
||||
minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE;
|
||||
if (minuteoffset < 10000000 || minuteoffset > 90000000)
|
||||
minuteoffset = MINUTEOFFSET;
|
||||
off64_t secsize = minuteoffset/60;
|
||||
off64_t secoffset = secsize * seconds;
|
||||
off64_t newsize = secoffset;
|
||||
|
||||
//printf("truncate: name %s size %lld len %d sec truncate to %d sec, new size %lld\n", name, size, len, seconds, secoffset);
|
||||
snprintf(spart, sizeof(spart), "%s", name);
|
||||
while (!stat64(spart, &s)) {
|
||||
if (found) {
|
||||
//printf("truncate: check part %d file %s - TO REMOVE\n", part, spart);
|
||||
unlink(spart);
|
||||
} else {
|
||||
//printf("truncate: check part %d file %s - OK\n", part, spart);
|
||||
if (secoffset < s.st_size) {
|
||||
tpart = part;
|
||||
found = 1;
|
||||
} else
|
||||
secoffset -= s.st_size;
|
||||
}
|
||||
snprintf(spart, sizeof(spart), "%s.%03d", name, ++part);
|
||||
}
|
||||
if (found) {
|
||||
if (tpart)
|
||||
snprintf(spart, sizeof(spart), "%s.%03d", name, tpart);
|
||||
else
|
||||
snprintf(spart, sizeof(spart), "%s", name);
|
||||
printf("truncate: part %s to size %" PRId64 "\n", spart, secoffset);
|
||||
truncate(spart, secoffset);
|
||||
minfo->file.Size = newsize;
|
||||
minfo->length = minfo->bookmarks.end/60;
|
||||
minfo->bookmarks.end = 0;
|
||||
reset_atime(spart, minfo->file.Time);
|
||||
return newsize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mybook {
|
||||
off64_t pos;
|
||||
off64_t len;
|
||||
bool ok;
|
||||
};
|
||||
#define REAL_CUT 1
|
||||
|
||||
static int check_pes_start (unsigned char *packet)
|
||||
{
|
||||
// PCKT: 47 41 91 37 07 50 3F 14 BF 04 FE B9 00 00 01 EA 00 00 8C ...
|
||||
if (packet[0] == 0x47 && // sync byte 0x47
|
||||
(packet[1] & 0x40)) // pusi == 1
|
||||
{
|
||||
/* good, now we have to check if it is video stream */
|
||||
unsigned char *pes = packet + 4;
|
||||
if (packet[3] & 0x20) // adaptation field is present
|
||||
pes += packet[4] + 1;
|
||||
|
||||
if (!memcmp(pes, "\x00\x00\x01", 3) && (pes[3] & 0xF0) == 0xE0) // PES start & video type
|
||||
{
|
||||
//return 1; //(pes[4] << 8) | pes[5]; // PES packet len
|
||||
pes += 4;
|
||||
while (pes < (packet + 188 - 4))
|
||||
if (!memcmp(pes, "\x00\x00\x01\xB8", 4)) // GOP detect
|
||||
return 1;
|
||||
else
|
||||
pes++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int find_gop(unsigned char *buf, int r)
|
||||
{
|
||||
for (int j = 0; j < r/188; j++) {
|
||||
if (check_pes_start(&buf[188*j])) {
|
||||
return 188*j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#if 0
|
||||
//never used
|
||||
off64_t fake_read(int fd, unsigned char *buf, size_t size, off64_t fsize)
|
||||
{
|
||||
off64_t cur = lseek64(fd, 0, SEEK_CUR);
|
||||
|
||||
buf[0] = 0x47;
|
||||
if((cur + size) > fsize)
|
||||
return(fsize - cur);
|
||||
else
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
#define PSI_SIZE 188*3
|
||||
static int read_psi(char * spart, unsigned char * buf)
|
||||
{
|
||||
int srcfd = open(spart, O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd >= 0) {
|
||||
/* read psi */
|
||||
int r = read(srcfd, buf, PSI_SIZE);
|
||||
close(srcfd);
|
||||
if (r != PSI_SIZE) {
|
||||
perror("read psi");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void save_info(CMovieInfo * cmovie, MI_MOVIE_INFO * minfo, char * dpart, off64_t spos, off64_t secsize)
|
||||
{
|
||||
MI_MOVIE_INFO ninfo = *minfo;
|
||||
ninfo.file.Name = dpart;
|
||||
ninfo.file.Size = spos;
|
||||
ninfo.length = spos/secsize/60;
|
||||
ninfo.bookmarks.end = 0;
|
||||
ninfo.bookmarks.start = 0;
|
||||
ninfo.bookmarks.lastPlayStop = 0;
|
||||
for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) {
|
||||
if (ninfo.bookmarks.user[book_nr].pos != 0 && ninfo.bookmarks.user[book_nr].length > 0) {
|
||||
ninfo.bookmarks.user[book_nr].pos = 0;
|
||||
ninfo.bookmarks.user[book_nr].length = 0;
|
||||
}
|
||||
}
|
||||
cmovie->saveMovieInfo(ninfo);
|
||||
reset_atime(dpart, minfo->file.Time);
|
||||
}
|
||||
|
||||
static void find_new_part(char * npart, char * dpart,size_t dpart_len)
|
||||
{
|
||||
struct stat64 s;
|
||||
int dp = 0;
|
||||
snprintf(dpart, dpart_len, "%s_%d.ts", npart, dp);
|
||||
while (!stat64(dpart, &s)) {
|
||||
snprintf(dpart, dpart_len, "%s_%d.ts", npart, ++dp);
|
||||
}
|
||||
}
|
||||
|
||||
int compare_book(const void *x, const void *y)
|
||||
{
|
||||
struct mybook * px, * py;
|
||||
int dx, dy;
|
||||
px = (struct mybook*) x;
|
||||
py = (struct mybook*) y;
|
||||
dx = px->pos / (off64_t) 1024;
|
||||
dy = py->pos / (off64_t) 1024;
|
||||
int res = dx - dy;
|
||||
//printf("SORT: %lld and %lld res %d\n", px->pos, py->pos, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int get_input(bool * stop)
|
||||
{
|
||||
neutrino_msg_data_t data;
|
||||
neutrino_msg_t msg;
|
||||
int retval = 0;
|
||||
* stop = false;
|
||||
g_RCInput->getMsg(&msg, &data, 1, false);
|
||||
if (msg == CRCInput::RC_home) {
|
||||
if (ShowMsg(LOCALE_MESSAGEBOX_INFO, "Cancel movie cut/split ?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) {
|
||||
* stop = true;
|
||||
}
|
||||
}
|
||||
if (msg != CRCInput::RC_timeout)
|
||||
retval |= 1;
|
||||
if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all)
|
||||
retval |= 2;
|
||||
//printf("input: msg %d (%x) ret %d\n", msg, msg, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static off64_t cut_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie)
|
||||
{
|
||||
struct mybook books[MI_MOVIE_BOOK_USER_MAX+2];
|
||||
int bcount = 0;
|
||||
int dstfd, srcfd;
|
||||
int part = 0;
|
||||
struct stat64 s;
|
||||
char spart[255];
|
||||
char dpart[255];
|
||||
char npart[255];
|
||||
|
||||
unsigned char psi[PSI_SIZE];
|
||||
int r, i;
|
||||
off64_t sdone, spos;
|
||||
off64_t newsize;
|
||||
time_t tt;
|
||||
int percent = 0;
|
||||
char * name = (char *) minfo->file.Name.c_str();
|
||||
CFile file;
|
||||
MI_MOVIE_INFO ninfo;
|
||||
bool need_gop = 0;
|
||||
off64_t tdone = 0;
|
||||
int was_cancel = 0;
|
||||
int retval = 0;
|
||||
time_t tt1;
|
||||
off64_t bpos, bskip;
|
||||
|
||||
unsigned char * buf = new unsigned char[BUF_SIZE];
|
||||
if (buf == 0) {
|
||||
perror("new");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFrameBuffer * frameBuffer = CFrameBuffer::getInstance();
|
||||
if (! timescale)
|
||||
timescale = new CProgressBar();
|
||||
timescale->setType(CProgressBar::PB_TIMESCALE);
|
||||
int dx = 256;
|
||||
int x = (((g_settings.screen_EndX- g_settings.screen_StartX)- dx) / 2) + g_settings.screen_StartX;
|
||||
int y = g_settings.screen_EndY - 50;
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0);//TODO: remove unneeded box paints
|
||||
timescale->setProgress(x + 41, y + 12, 200, 15, percent, 100);
|
||||
timescale->paint();
|
||||
int len = minfo->length;
|
||||
off64_t size = minfo->file.Size;
|
||||
//off64_t secsize = len ? size/len/60 : 511040;
|
||||
off64_t minuteoffset = len ? size / len : MINUTEOFFSET;
|
||||
minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE;
|
||||
if (minuteoffset < 5000000 || minuteoffset > 190000000)
|
||||
minuteoffset = MINUTEOFFSET;
|
||||
off64_t secsize = minuteoffset/60;
|
||||
newsize = size;
|
||||
|
||||
if (minfo->bookmarks.start != 0) {
|
||||
books[bcount].pos = 0;
|
||||
books[bcount].len = (minfo->bookmarks.start * secsize)/188 * 188;
|
||||
if (books[bcount].len > SAFE_GOP)
|
||||
books[bcount].len -= SAFE_GOP;
|
||||
books[bcount].ok = 1;
|
||||
printf("cut: start bookmark %d at %" PRId64 " len %" PRId64 "\n", bcount, books[bcount].pos, books[bcount].len);
|
||||
bcount++;
|
||||
}
|
||||
for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) {
|
||||
if (minfo->bookmarks.user[book_nr].pos != 0 && minfo->bookmarks.user[book_nr].length > 0) {
|
||||
books[bcount].pos = (minfo->bookmarks.user[book_nr].pos * secsize)/188 * 188;
|
||||
books[bcount].len = (minfo->bookmarks.user[book_nr].length * secsize)/188 * 188;
|
||||
if (books[bcount].len > SAFE_GOP)
|
||||
books[bcount].len -= SAFE_GOP;
|
||||
books[bcount].ok = 1;
|
||||
printf("cut: jump bookmark %d at %" PRId64 " len %" PRId64 " -> skip to %" PRId64 "\n", bcount, books[bcount].pos, books[bcount].len, books[bcount].pos+books[bcount].len);
|
||||
bcount++;
|
||||
}
|
||||
}
|
||||
if (minfo->bookmarks.end != 0) {
|
||||
books[bcount].pos = ((off64_t) minfo->bookmarks.end * secsize)/188 * 188;
|
||||
books[bcount].len = size - books[bcount].pos;
|
||||
//if (books[bcount].pos > SAFE_GOP)
|
||||
// books[bcount].pos -= SAFE_GOP;
|
||||
books[bcount].ok = 1;
|
||||
printf("cut: end bookmark %d at %" PRId64 "\n", bcount, books[bcount].pos);
|
||||
bcount++;
|
||||
}
|
||||
printf("\n");
|
||||
if (!bcount) {
|
||||
delete [] buf;
|
||||
return 0;
|
||||
}
|
||||
qsort(books, bcount, sizeof(struct mybook), compare_book);
|
||||
for (i = 0; i < bcount; i++) {
|
||||
if (books[i].ok) {
|
||||
printf("cut: bookmark %d at %" PRId64 " len %" PRId64 " -> skip to %" PRId64 "\n", i, books[i].pos, books[i].len, books[i].pos+books[i].len);
|
||||
newsize -= books[i].len;
|
||||
off64_t curend = books[i].pos + books[i].len;
|
||||
for (int j = i + 1; j < bcount; j++) {
|
||||
if ((books[j].pos > books[i].pos) && (books[j].pos < curend)) {
|
||||
off64_t newend = books[j].pos + books[j].len;
|
||||
if (newend > curend) {
|
||||
printf("cut: bad bookmark %d, position %" PRId64 " len %" PRId64 ", ajusting..\n", j, books[j].pos, books[j].len);
|
||||
books[j].pos = curend;
|
||||
books[j].len = newend - curend;
|
||||
} else {
|
||||
printf("cut: bad bookmark %d, position %" PRId64 " len %" PRId64 ", skipping..\n", j, books[j].pos, books[j].len);
|
||||
books[j].ok = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
snprintf(npart, sizeof(npart), "%s", name);
|
||||
char * ptr = strstr(npart+strlen(npart)-3, ".ts");
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
find_new_part(npart, dpart, sizeof(dpart));
|
||||
tt = time(0);
|
||||
printf("\n********* new file %s expected size %" PRId64 ", start time %s", dpart, newsize, ctime(&tt));
|
||||
dstfd = open(dpart, O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE, 0644);
|
||||
if (dstfd < 0) {
|
||||
perror(dpart);
|
||||
delete [] buf;
|
||||
return 0;
|
||||
}
|
||||
part = 0;
|
||||
i = 0;
|
||||
off64_t offset = 0;
|
||||
spos = 0;
|
||||
snprintf(spart, sizeof(spart), "%s", name);
|
||||
if (read_psi(spart, &psi[0])) {
|
||||
perror(spart);
|
||||
goto ret_err;
|
||||
}
|
||||
write(dstfd, psi, PSI_SIZE);
|
||||
bpos = books[i].pos;
|
||||
bskip = books[i].len;
|
||||
while (!stat64(spart, &s)) {
|
||||
printf("cut: open part %d file %s size %" PRId64 " offset %" PRId64 " book pos %" PRId64 "\n", part, spart, s.st_size, offset, bpos);
|
||||
srcfd = open(spart, O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd < 0) {
|
||||
perror(spart);
|
||||
goto ret_err;
|
||||
}
|
||||
if (offset >= s.st_size) {
|
||||
offset -= s.st_size;
|
||||
bpos -= s.st_size;
|
||||
goto next_file;
|
||||
}
|
||||
lseek64(srcfd, offset, SEEK_SET);
|
||||
sdone = offset;
|
||||
while (true) {
|
||||
off64_t until = bpos;
|
||||
printf("\ncut: reading from %" PRId64 " to %" PRId64 " (%" PRId64 ") want gop %d\n", sdone, until, until - sdone, need_gop);
|
||||
while (sdone < until) {
|
||||
bool stop;
|
||||
int msg = get_input(&stop);
|
||||
was_cancel = msg & 2;
|
||||
if (stop) {
|
||||
close(srcfd);
|
||||
unlink(dpart);
|
||||
retval = 1;
|
||||
goto ret_err;
|
||||
}
|
||||
if (msg) {
|
||||
timescale->reset();
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0);//TODO: remove unneeded box paints
|
||||
}
|
||||
size_t toread = (until-sdone) > BUF_SIZE ? BUF_SIZE : until - sdone;
|
||||
#if REAL_CUT
|
||||
r = read(srcfd, buf, toread);
|
||||
#else
|
||||
r = fake_read(srcfd, buf, toread, s.st_size);
|
||||
#endif
|
||||
if (r > 0) {
|
||||
int wptr = 0;
|
||||
// FIXME: TEST
|
||||
if (r != BUF_SIZE) printf("****** short read ? %d\n", r);
|
||||
if (buf[0] != 0x47) printf("cut: buffer not aligned at %" PRId64 "\n", sdone);
|
||||
if (need_gop) {
|
||||
int gop = find_gop(buf, r);
|
||||
if (gop >= 0) {
|
||||
printf("cut: GOP found at %" PRId64 " offset %d\n", (off64_t)(sdone+gop), gop);
|
||||
newsize -= gop;
|
||||
wptr = gop;
|
||||
} else
|
||||
printf("cut: GOP needed, but not found\n");
|
||||
need_gop = 0;
|
||||
}
|
||||
sdone += r;
|
||||
spos += r - wptr;
|
||||
percent = spos * 100 / newsize;
|
||||
timescale->setProgress(x + 41, y + 12, 200, 15, percent, 100);
|
||||
timescale->paint();
|
||||
#if REAL_CUT
|
||||
int wr = write(dstfd, &buf[wptr], r-wptr);
|
||||
if (wr < (r-wptr)) {
|
||||
perror(dpart);
|
||||
close(srcfd);
|
||||
goto ret_err;
|
||||
}
|
||||
#endif
|
||||
} else if (sdone < s.st_size) {
|
||||
/* read error ? */
|
||||
close(srcfd);
|
||||
perror(spart);
|
||||
goto ret_err;
|
||||
} else {
|
||||
printf("cut: next file -> sdone %" PRId64 " spos %" PRId64 " bpos %" PRId64 "\n", sdone, spos, bpos);
|
||||
offset = 0;
|
||||
bpos -= sdone;
|
||||
goto next_file;
|
||||
}
|
||||
}
|
||||
printf("cut: current file pos %" PRId64 " write pos %" PRId64 " book pos %" PRId64 " still to read %" PRId64 "\n", sdone, spos, bpos, sdone - bpos);
|
||||
need_gop = 1;
|
||||
offset = bpos + bskip;
|
||||
i++;
|
||||
while (i < bcount) {
|
||||
if (books[i].ok)
|
||||
break;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (i < bcount) {
|
||||
bpos = books[i].pos;
|
||||
bskip = books[i].len;
|
||||
} else
|
||||
bpos = size;
|
||||
printf("cut: next bookmark pos: %" PRId64 " abs %" PRId64 " relative next file pos %" PRId64 " cur file size %" PRId64 "\n", bpos, bpos - tdone, offset, s.st_size);
|
||||
bpos -= tdone; /* all books from 0, converting to 0 + total size skipped */
|
||||
if (offset >= s.st_size) {
|
||||
offset -= s.st_size;
|
||||
bpos -= s.st_size;
|
||||
goto next_file;
|
||||
}
|
||||
lseek64(srcfd, offset, SEEK_SET);
|
||||
sdone = offset;
|
||||
}
|
||||
next_file:
|
||||
tdone += s.st_size;
|
||||
close(srcfd);
|
||||
snprintf(spart, sizeof(spart), "%s.%03d", name, ++part);
|
||||
}
|
||||
tt1 = time(0);
|
||||
printf("********* total written %" PRId64 " tooks %ld secs end time %s", spos, tt1-tt, ctime(&tt1));
|
||||
|
||||
save_info(cmovie, minfo, dpart, spos, secsize);
|
||||
retval = 1;
|
||||
lseek64(dstfd, 0, SEEK_SET);
|
||||
ret_err:
|
||||
close(dstfd);
|
||||
delete [] buf;
|
||||
if (was_cancel)
|
||||
g_RCInput->postMsg(CRCInput::RC_home, 0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static off64_t copy_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie, bool onefile)
|
||||
{
|
||||
struct mybook books[MI_MOVIE_BOOK_USER_MAX+2];
|
||||
int bcount = 0;
|
||||
int dstfd = -1, srcfd;
|
||||
int part = 0;
|
||||
struct stat64 s;
|
||||
char spart[255];
|
||||
char dpart[255];
|
||||
char npart[255];
|
||||
unsigned char psi[PSI_SIZE];
|
||||
int r, i;
|
||||
off64_t sdone, spos = 0, btotal = 0;
|
||||
off64_t newsize;
|
||||
time_t tt;
|
||||
int percent = 0;
|
||||
char * name = (char *) minfo->file.Name.c_str();
|
||||
CFile file;
|
||||
bool need_gop = 0;
|
||||
bool dst_done = 0;
|
||||
bool was_cancel = false;
|
||||
int retval = 0;
|
||||
|
||||
unsigned char * buf = new unsigned char[BUF_SIZE];
|
||||
if (buf == 0) {
|
||||
perror("new");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int len = minfo->length;
|
||||
off64_t size = minfo->file.Size;
|
||||
off64_t minuteoffset = len ? size / len : MINUTEOFFSET;
|
||||
minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE;
|
||||
if (minuteoffset < 5000000 || minuteoffset > 190000000)
|
||||
minuteoffset = MINUTEOFFSET;
|
||||
off64_t secsize = minuteoffset/60;
|
||||
//off64_t secsize = len ? size/len/60 : 511040;
|
||||
printf("copy: len %d minute %" PRId64 " second %" PRId64 "\n", len, len ? size/len : 511040*60, secsize);
|
||||
|
||||
CFrameBuffer * frameBuffer = CFrameBuffer::getInstance();
|
||||
if (!timescale)
|
||||
timescale = new CProgressBar();
|
||||
timescale->setType(CProgressBar::PB_TIMESCALE);
|
||||
int dx = 256;
|
||||
int x = (((g_settings.screen_EndX- g_settings.screen_StartX)- dx) / 2) + g_settings.screen_StartX;
|
||||
int y = g_settings.screen_EndY - 50;
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0); //TODO: remove unneeded box paints
|
||||
timescale->setProgress(x + 41, y + 12, 200, 15, percent, 100);
|
||||
timescale->paint();
|
||||
|
||||
newsize = 0;
|
||||
for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) {
|
||||
if (minfo->bookmarks.user[book_nr].pos != 0 && minfo->bookmarks.user[book_nr].length > 0) {
|
||||
books[bcount].pos = (minfo->bookmarks.user[book_nr].pos * secsize)/188 * 188;
|
||||
if (books[bcount].pos > SAFE_GOP)
|
||||
books[bcount].pos -= SAFE_GOP;
|
||||
books[bcount].len = (minfo->bookmarks.user[book_nr].length * secsize)/188 * 188;
|
||||
books[bcount].ok = 1;
|
||||
printf("copy: jump bookmark %d at %" PRId64 " len %" PRId64 "\n", bcount, books[bcount].pos, books[bcount].len);
|
||||
newsize += books[bcount].len;
|
||||
bcount++;
|
||||
}
|
||||
}
|
||||
if (!bcount) {
|
||||
delete [] buf;
|
||||
return 0;
|
||||
}
|
||||
tt = time(0);
|
||||
printf("********* %d boormarks, to %s file(s), expected size to copy %" PRId64 ", start time %s", bcount, onefile ? "one" : "many", newsize, ctime(&tt));
|
||||
snprintf(npart, sizeof(npart), "%s", name);
|
||||
char * ptr = strstr(npart+strlen(npart)-3, ".ts");
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
snprintf(spart, sizeof(spart), "%s", name);
|
||||
srcfd = open(spart, O_RDONLY | O_LARGEFILE);
|
||||
if (read_psi(spart, &psi[0])) {
|
||||
perror(spart);
|
||||
goto ret_err;
|
||||
}
|
||||
for (i = 0; i < bcount; i++) {
|
||||
printf("\ncopy: processing bookmark %d at %" PRId64 " len %" PRId64 "\n", i, books[i].pos, books[i].len);
|
||||
off64_t bpos = books[i].pos;
|
||||
off64_t bskip = books[i].len;
|
||||
part = 0;
|
||||
snprintf(spart, sizeof(spart), "%s", name);
|
||||
int sres;
|
||||
while (!(sres = stat64(spart, &s))) {
|
||||
if (bpos >= s.st_size) {
|
||||
bpos -= s.st_size;
|
||||
snprintf(spart, sizeof(spart), "%s.%03d", name, ++part);
|
||||
//printf("copy: check src part %s\n", spart);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (sres != 0) {
|
||||
printf("file for bookmark %d with offset %" PRId64 " not found\n", i, books[i].pos);
|
||||
continue;
|
||||
}
|
||||
if (!dst_done || !onefile) {
|
||||
find_new_part(npart, dpart, sizeof(dpart));
|
||||
dstfd = open(dpart, O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE, 0644);
|
||||
printf("copy: new file %s fd %d\n", dpart, dstfd);
|
||||
if (dstfd < 0) {
|
||||
printf("failed to open %s\n", dpart);
|
||||
goto ret_err;;
|
||||
}
|
||||
dst_done = 1;
|
||||
spos = 0;
|
||||
write(dstfd, psi, PSI_SIZE);
|
||||
}
|
||||
need_gop = 1;
|
||||
next_file:
|
||||
stat64(spart, &s);
|
||||
printf("copy: open part %d file %s size %" PRId64 " offset %" PRId64 "\n", part, spart, s.st_size, bpos);
|
||||
srcfd = open(spart, O_RDONLY | O_LARGEFILE);
|
||||
if (srcfd < 0) {
|
||||
printf("failed to open %s\n", spart);
|
||||
close(dstfd);
|
||||
goto ret_err;
|
||||
}
|
||||
lseek64(srcfd, bpos, SEEK_SET);
|
||||
sdone = bpos;
|
||||
off64_t until = bpos + bskip;
|
||||
printf("copy: read from %" PRId64 " to %" PRId64 " read size %d want gop %d\n", bpos, until, BUF_SIZE, need_gop);
|
||||
while (sdone < until) {
|
||||
size_t toread = (until-sdone) > BUF_SIZE ? BUF_SIZE : until - sdone;
|
||||
bool stop;
|
||||
int msg = get_input(&stop);
|
||||
was_cancel = msg & 2;
|
||||
if (stop) {
|
||||
close(srcfd);
|
||||
close(dstfd);
|
||||
unlink(dpart);
|
||||
retval = 1;
|
||||
goto ret_err;
|
||||
}
|
||||
if (msg) {
|
||||
frameBuffer->paintBoxRel(x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0);//TODO: remove unneeded box paints
|
||||
timescale->reset();
|
||||
}
|
||||
#if REAL_CUT
|
||||
r = read(srcfd, buf, toread);
|
||||
#else
|
||||
r = fake_read(srcfd, buf, toread, s.st_size);
|
||||
#endif
|
||||
if (r > 0) {
|
||||
int wptr = 0;
|
||||
// FIXME: TEST
|
||||
if (r != BUF_SIZE) printf("****** short read ? %d\n", r);
|
||||
if (buf[0] != 0x47) printf("copy: buffer not aligned at %" PRId64 "\n", sdone);
|
||||
if (need_gop) {
|
||||
int gop = find_gop(buf, r);
|
||||
if (gop >= 0) {
|
||||
printf("cut: GOP found at %" PRId64 " offset %d\n", (off64_t)(sdone+gop), gop);
|
||||
newsize -= gop;
|
||||
wptr = gop;
|
||||
} else
|
||||
printf("cut: GOP needed, but not found\n");
|
||||
need_gop = 0;
|
||||
}
|
||||
sdone += r;
|
||||
bskip -= r;
|
||||
spos += r - wptr;
|
||||
btotal += r;
|
||||
percent = btotal * 100 / newsize;
|
||||
timescale->setProgress(x + 41, y + 12, 200, 15, percent, 100);
|
||||
timescale->paint();
|
||||
#if REAL_CUT
|
||||
int wr = write(dstfd, &buf[wptr], r-wptr);
|
||||
if (wr < (r-wptr)) {
|
||||
printf("write to %s failed\n", dpart);
|
||||
close(srcfd);
|
||||
close(dstfd);
|
||||
goto ret_err;
|
||||
}
|
||||
#endif
|
||||
} else if (sdone < s.st_size) {
|
||||
/* read error ? */
|
||||
printf("%s: read failed\n", spart);
|
||||
close(srcfd);
|
||||
close(dstfd);
|
||||
goto ret_err;
|
||||
} else {
|
||||
printf("copy: -> next file, file pos %" PRId64 " written %" PRId64 " left %" PRId64 "\n", sdone, spos, bskip);
|
||||
bpos = 0;
|
||||
close(srcfd);
|
||||
snprintf(spart, sizeof(spart), "%s.%03d", name, ++part);
|
||||
goto next_file;
|
||||
}
|
||||
} /* while(sdone < until) */
|
||||
close(srcfd);
|
||||
|
||||
if (!onefile) {
|
||||
close(dstfd);
|
||||
save_info(cmovie, minfo, dpart, spos, secsize);
|
||||
time_t tt1 = time(0);
|
||||
printf("copy: ********* %s: total written %" PRId64 " took %ld secs\n", dpart, spos, tt1-tt);
|
||||
}
|
||||
} /* for all books */
|
||||
if (onefile) {
|
||||
close(dstfd);
|
||||
save_info(cmovie, minfo, dpart, spos, secsize);
|
||||
time_t tt1 = time(0);
|
||||
printf("copy: ********* %s: total written %" PRId64 " took %ld secs\n", dpart, spos, tt1-tt);
|
||||
}
|
||||
retval = 1;
|
||||
ret_err:
|
||||
delete [] buf;
|
||||
if (was_cancel)
|
||||
g_RCInput->postMsg(CRCInput::RC_home, 0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
@@ -1504,16 +1504,23 @@ void CMoviePlayerGui::handleMovieBrowser(neutrino_msg_t msg, int /*position*/)
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_HEAD, !isMovieBrowser, NULL, &cSelectedMenuBookStart[0]));
|
||||
bookStartMenu.addItem(GenericMenuSeparatorLine);
|
||||
#endif
|
||||
const char *unit_short_minute = g_Locale->getText(LOCALE_UNIT_SHORT_MINUTE);
|
||||
char play_pos[32];
|
||||
snprintf(play_pos, sizeof(play_pos), "%3d %s", p_movie_info->bookmarks.lastPlayStop/60, g_Locale->getText(LOCALE_UNIT_SHORT_MINUTE));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_LASTMOVIESTOP, isMovieBrowser, play_pos, &cSelectedMenuBookStart[1]));
|
||||
snprintf(play_pos, sizeof(play_pos), "%3d %s", p_movie_info->bookmarks.lastPlayStop/60, unit_short_minute);
|
||||
char start_pos[32] = {0};
|
||||
if (p_movie_info->bookmarks.start != 0)
|
||||
snprintf(start_pos, sizeof(start_pos), "%3d %s", p_movie_info->bookmarks.start/60, unit_short_minute);
|
||||
char end_pos[32] = {0};
|
||||
if (p_movie_info->bookmarks.end != 0)
|
||||
snprintf(end_pos, sizeof(end_pos), "%3d %s", p_movie_info->bookmarks.end/60, unit_short_minute);
|
||||
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_LASTMOVIESTOP, isMovieBrowser, play_pos, &cSelectedMenuBookStart[1]));
|
||||
bookStartMenu.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MOVIEBROWSER_BOOK_ADD));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_NEW, isMovieBrowser, NULL, &cSelectedMenuBookStart[2]));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_TYPE_FORWARD, isMovieBrowser, NULL, &cSelectedMenuBookStart[3]));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_TYPE_BACKWARD, isMovieBrowser, NULL, &cSelectedMenuBookStart[4]));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, isMovieBrowser, NULL, &cSelectedMenuBookStart[5]));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIEEND, isMovieBrowser, NULL, &cSelectedMenuBookStart[6]));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, isMovieBrowser, start_pos, &cSelectedMenuBookStart[5]));
|
||||
bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIEEND, isMovieBrowser, end_pos, &cSelectedMenuBookStart[6]));
|
||||
|
||||
// no, nothing else to do, we open a new bookmark menu
|
||||
new_bookmark.name = ""; // use default name
|
||||
@@ -1567,7 +1574,7 @@ void CMoviePlayerGui::handleMovieBrowser(neutrino_msg_t msg, int /*position*/)
|
||||
} else if (cSelectedMenuBookStart[6].selected == true) {
|
||||
/* Moviebrowser movie end bookmark */
|
||||
p_movie_info->bookmarks.end = play_sec;
|
||||
TRACE("[mp] New movie end pos: %d\r\n", p_movie_info->bookmarks.start);
|
||||
TRACE("[mp] New movie end pos: %d\r\n", p_movie_info->bookmarks.end);
|
||||
cMovieInfo.saveMovieInfo(*p_movie_info); /* save immediately in xml file */
|
||||
}
|
||||
}
|
||||
|
@@ -1336,7 +1336,7 @@ void CMenuWidget::paintHint(int pos)
|
||||
//init details line and infobox dimensions
|
||||
int ypos1 = item->getYPosition();
|
||||
int ypos1a = ypos1 + (iheight/2)-2;
|
||||
int ypos2a = ypos2 + (hint_height/2) - INFO_BOX_Y_OFFSET;
|
||||
int ypos2a = ypos2 + (hint_height/2)-2;
|
||||
int markh = hint_height > rad*2 ? hint_height - rad*2 : hint_height;
|
||||
int imarkh = iheight/2+1;
|
||||
|
||||
|
Reference in New Issue
Block a user