diff --git a/src/driver/Makefile.am b/src/driver/Makefile.am index cd96e9f66..0c115ed16 100644 --- a/src/driver/Makefile.am +++ b/src/driver/Makefile.am @@ -31,6 +31,7 @@ libneutrino_driver_a_SOURCES = \ fontrenderer.cpp \ framebuffer_ng.cpp \ genpsi.cpp \ + moviecut.cpp \ neutrinofonts.cpp \ radiotext.cpp \ radiotools.cpp \ diff --git a/src/driver/moviecut.cpp b/src/driver/moviecut.cpp new file mode 100644 index 000000000..1810c676d --- /dev/null +++ b/src/driver/moviecut.cpp @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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; +} diff --git a/src/driver/moviecut.h b/src/driver/moviecut.h new file mode 100644 index 000000000..c996ebaab --- /dev/null +++ b/src/driver/moviecut.h @@ -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 +#include +#include + +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 diff --git a/src/gui/moviebrowser.cpp b/src/gui/moviebrowser.cpp index c5964fba6..401efac60 100644 --- a/src/gui/moviebrowser.cpp +++ b/src/gui/moviebrowser.cpp @@ -68,23 +68,18 @@ #include #include #include +#include #include #include 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 diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 0bb58d01e..530919d94 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -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 */ } } diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index e7c06181d..fe585566e 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -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;