From 5ce1a1023a2b6f557c5bd5ddcc114f9dbfbd5cb0 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Sat, 14 Aug 2010 16:10:45 +0200 Subject: [PATCH] libtriple: implement fast forward in cPlayback() First try at implementing fast forward. Needs more love. Reverse does not work yet, setting speed to negative values right now simply resets to "play" mode. Origin commit data ------------------ Branch: ni/coolstream Commit: https://github.com/neutrino-images/ni-neutrino/commit/a3440d19df22b2a47157032dc299d49c8429044b Author: Stefan Seyfried Date: 2010-08-14 (Sat, 14 Aug 2010) ------------------ This commit was generated by Migit --- lib/libtriple/playback_td.cpp | 158 ++++++++++++++++++++++++++++------ lib/libtriple/video_td.cpp | 6 ++ lib/libtriple/video_td.h | 1 + 3 files changed, 138 insertions(+), 27 deletions(-) diff --git a/lib/libtriple/playback_td.cpp b/lib/libtriple/playback_td.cpp index 59dd37cd0..e8ff878c2 100644 --- a/lib/libtriple/playback_td.cpp +++ b/lib/libtriple/playback_td.cpp @@ -329,15 +329,30 @@ bool cPlayback::SetAPid(unsigned short pid, bool _ac3) bool cPlayback::SetSpeed(int speed) { INFO("speed = %d\n", speed); - if (speed != 0 && playback_speed == 0) + if (speed < 0) + speed = 1; /* fast rewind not yet implemented... */ + if (speed == 1 && playback_speed != 1) { - videoDemux->Stop(); - videoDemux->Start(); - audioDemux->Start(); + if (playback_speed == 0) + { + videoDemux->Stop(); + videoDemux->Start(); + audioDemux->Start(); + } + else + { + audioDecoder->Stop(); + videoDecoder->Stop(); + } audioDecoder->Start(); videoDecoder->Start(); playstate = STATE_PLAY; } + if (playback_speed == 1 && speed > 1) + { + audioDecoder->mute(false); + videoDecoder->FastForwardMode(); + } playback_speed = speed; if (playback_speed == 0) { @@ -698,46 +713,135 @@ ssize_t cPlayback::read_ts() ssize_t toread, ret = 0, sync, off; toread = INBUF_SIZE - inbuf_pos; bool retry = true; + uint8_t *buf; /* fprintf(stderr, "%s:%d curr_pos %lld, inbuf_pos: %ld, toread: %ld\n", __FUNCTION__, __LINE__, (long long)curr_pos, (long)inbuf_pos, (long)toread); */ - while(true) + if (playback_speed > 1) { - ret = read(in_fd, inbuf + inbuf_pos, toread); - if (ret == 0 && retry) /* EOF */ + sync = 0; + ssize_t tmpread = PESBUF_SIZE / 188 * 188; + int n, skipped = 0; + bool skip = false; + bool eof = true; + while (toread > 0) { - mf_lseek(curr_pos); - retry = false; - continue; + ssize_t done = 0; + while (done < tmpread) + { + ret = read(in_fd, pesbuf, tmpread - done); + if (ret == 0 && retry) /* EOF */ + { + mf_lseek(curr_pos); + retry = false; + continue; + } + if (ret < 0) + { + INFO("failed: %m\n"); + return ret; + } + if (ret == 0 && eof) + goto out; + eof = false; + done += ret; + curr_pos += ret; + } + sync = sync_ts(pesbuf, ret); + if (sync != 0) + { + INFO("out of sync: %d\n", sync); + if (sync < 0) + { + return -1; + } + memmove(pesbuf, pesbuf + sync, ret - sync); + if (pesbuf[0] != 0x47) + INFO("??????????????????????????????\n"); + } + for (n = 0; n < done / 188 * 188; n += 188) + { + buf = pesbuf + n; + if (buf[1] & 0x40) // PUSI + { + /* only video packets... */ + int of = 4; + if (buf[3] & 0x20) // adaptation field + of += buf[4] + 1; + if ((buf[of + 3] & 0xF0) == 0xE0 && // Video stream + buf[of + 2] == 0x01 && buf[of + 1] == 0x00 && buf[of] == 0x00) // PES + { + skip = true; + skipped++; + if (skipped >= playback_speed) + { + skipped = 0; + skip = false; + } + } + } + if (! skip) + { + memcpy(inbuf + inbuf_pos, buf, 188); + inbuf_pos += 188; + toread -= 188; + if (toread <= 0) + { + /* the output buffer is full, discard the input :-( */ + if (done - n > 0) + { + DBG("not done: %d, resetting filepos\n", done - n); + mf_lseek(curr_pos - (done - n)); + } + break; + } + } + } } - break; + out: + if (eof) + return 0; } - if (ret < 0) + else { - INFO("failed: %m\n"); - return ret; - } - if (ret == 0) - return ret; - inbuf_pos += ret; - curr_pos += ret; + while(true) + { + ret = read(in_fd, inbuf + inbuf_pos, toread); + if (ret == 0 && retry) /* EOF */ + { + mf_lseek(curr_pos); + retry = false; + continue; + } + break; + } + if (ret < 0) + { + INFO("failed: %m\n"); + return ret; + } + if (ret == 0) + return ret; + inbuf_pos += ret; + curr_pos += ret; - sync = sync_ts(inbuf + inbuf_sync, INBUF_SIZE - inbuf_sync); - if (sync < 0) - { - INFO("cannot sync\n"); - return ret; + sync = sync_ts(inbuf + inbuf_sync, INBUF_SIZE - inbuf_sync); + if (sync < 0) + { + INFO("cannot sync\n"); + return ret; + } + inbuf_sync += sync; } - inbuf_sync += sync; /* check for A/V PIDs */ uint16_t pid; int i, j; bool pid_new; int64_t pts; - // fprintf(stderr, "inbuf_pos: %ld - sync: %ld\n", (long)inbuf_pos, (long)sync); + //fprintf(stderr, "inbuf_pos: %ld - sync: %ld, inbuf_syc: %ld\n", (long)inbuf_pos, (long)sync, (long)inbuf_sync); int synccnt = 0; for (i = 0; i < inbuf_pos - inbuf_sync - 13;) { - uint8_t *buf = inbuf + inbuf_sync + i; + buf = inbuf + inbuf_sync + i; if (*buf != 0x47) { synccnt++; diff --git a/lib/libtriple/video_td.cpp b/lib/libtriple/video_td.cpp index b1a8cada5..8149deddf 100644 --- a/lib/libtriple/video_td.cpp +++ b/lib/libtriple/video_td.cpp @@ -644,3 +644,9 @@ void cVideo::routeVideo(int standby) perror("IOC_AVS_ROUTE_ENC2TV"); close(avsfd); } + +void cVideo::FastForwardMode(int mode) +{ + lt_debug("cVideo::%s\n", __FUNCTION__); + fop(ioctl, MPEG_VID_FASTFORWARD, mode); +} diff --git a/lib/libtriple/video_td.h b/lib/libtriple/video_td.h index 49778b12a..8a9f4f03b 100644 --- a/lib/libtriple/video_td.h +++ b/lib/libtriple/video_td.h @@ -179,6 +179,7 @@ class cVideo void SetVideoMode(analog_mode_t mode); void SetDBDR(int) { return; }; void SetAudioHandle(void *) { return; }; + void FastForwardMode(int mode = 0); void SetAutoModes(int [VIDEO_STD_MAX]) { return; }; int OpenVBI(int) { return 0; }; int CloseVBI(void) { return 0; };