From: Carl Hetherington Date: Sat, 15 Jun 2013 16:05:58 +0000 (+0100) Subject: Merge master. X-Git-Tag: v2.0.48~1337^2~324 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=a183c1776cfd020a37d028ebb0f641352f49697b Merge master. --- a183c1776cfd020a37d028ebb0f641352f49697b diff --cc icons/make_icns.sh index 983379ea4,983379ea4..522e907a6 --- a/icons/make_icns.sh +++ b/icons/make_icns.sh @@@ -1,4 -1,4 +1,4 @@@ #!/bin/bash --iconutil --convert icns --output dvdomatic.icns dvdomatic.iconset/ ++iconutil --convert icns --output dcpomatic.icns dcpomatic.iconset/ diff --cc platform/linux/dvdomatic.desktop.in index 65067eb3b,65067eb3b..000000000 deleted file mode 100644,100644 --- a/platform/linux/dvdomatic.desktop.in +++ /dev/null @@@ -1,10 -1,10 +1,0 @@@ --[Desktop Entry] --Encoding=UTF-8 --Version=1.0 --Type=Application --Terminal=false --Exec=@PREFIX@/bin/dvdomatic --Name=DVD-o-matic --Icon=dvdomatic --Comment=DCP generator --Categories=AudioVideo;Video diff --cc platform/linux/dvdomatic_batch.desktop.in index 8150fe849,8150fe849..000000000 deleted file mode 100644,100644 --- a/platform/linux/dvdomatic_batch.desktop.in +++ /dev/null @@@ -1,10 -1,10 +1,0 @@@ --[Desktop Entry] --Encoding=UTF-8 --Version=1.0 --Type=Application --Terminal=false --Exec=@PREFIX@/bin/dvdomatic_batch --Name=DVD-o-matic Batch Converter --Icon=dvdomatic --Comment=Batch DCP generator --Categories=AudioVideo;Video diff --cc platform/linux/servomatic.desktop.in index 572b4c64c,572b4c64c..000000000 deleted file mode 100644,100644 --- a/platform/linux/servomatic.desktop.in +++ /dev/null @@@ -1,10 -1,10 +1,0 @@@ --[Desktop Entry] --Encoding=UTF-8 --Version=1.0 --Type=Application --Terminal=false --Exec=@PREFIX@/bin/servomatic_gui --Name=DVD-o-matic Encode Server --Icon=dvdomatic --Comment=DCP generator --Categories=AudioVideo;Video diff --cc platform/linux/wscript index 1d9054b32,1d9054b32..53a6efeac --- a/platform/linux/wscript +++ b/platform/linux/wscript @@@ -2,18 -2,18 +2,18 @@@ def build(bld) d = { 'PREFIX' : '${PREFIX' } obj = bld(features = 'subst') -- obj.source = 'dvdomatic.desktop.in' -- obj.target = 'dvdomatic.desktop' ++ obj.source = 'dcpomatic.desktop.in' ++ obj.target = 'dcpomatic.desktop' obj.dict = d obj = bld(features = 'subst') -- obj.source = 'dvdomatic_batch.desktop.in' -- obj.target = 'dvdomatic_batch.desktop' ++ obj.source = 'dcpomatic_batch.desktop.in' ++ obj.target = 'dcpomatic_batch.desktop' obj.dict = d obj = bld(features = 'subst') -- obj.source = 'servomatic.desktop.in' -- obj.target = 'servomatic.desktop' ++ obj.source = 'dcpomatic_server.desktop.in' ++ obj.target = 'dcpomatic_server.desktop' obj.dict = d -- bld.install_files('${PREFIX}/share/applications', ['dvdomatic.desktop', 'dvdomatic_batch.desktop', 'servomatic.desktop']) ++ bld.install_files('${PREFIX}/share/applications', ['dcpomatic.desktop', 'dcpomatic_batch.desktop', 'dcpomatic_server.desktop']) diff --cc platform/osx/Info.plist.in index c904d91dd,c904d91dd..0f6774138 --- a/platform/osx/Info.plist.in +++ b/platform/osx/Info.plist.in @@@ -5,17 -5,17 +5,17 @@@ CFBundleDevelopmentRegion English CFBundleExecutable -- dvdomatic ++ dcpomatic CFBundleGetInfoString DCP generator CFBundleIconFile -- DVD-o-matic.icns ++ DCP-o-matic.icns CFBundleIdentifier -- net.carlh.dvdomatic ++ net.carlh.dcpomatic CFBundleInfoDictionaryVersion 6.0 CFBundleName -- DVD-o-matic ++ DCP-o-matic CFBundlePackageType APPL CFBundleShortVersions diff --cc platform/osx/make_dmg.sh index d9e36c390,f757eda34..1fcdc6d06 --- a/platform/osx/make_dmg.sh +++ b/platform/osx/make_dmg.sh @@@ -19,9 -19,9 +19,9 @@@ mkdir -p $WORK/$maco mkdir -p $WORK/$libs mkdir -p $WORK/$resources --cp build/src/tools/dvdomatic $WORK/$macos/ --cp build/src/lib/libdvdomatic.dylib $WORK/$libs/ --cp build/src/wx/libdvdomatic-wx.dylib $WORK/$libs/ ++cp build/src/tools/dcpomatic $WORK/$macos/ ++cp build/src/lib/libdcpomatic.dylib $WORK/$libs/ ++cp build/src/wx/libdcpomatic-wx.dylib $WORK/$libs/ cp $DEPS/lib/libdcp.dylib $WORK/$libs/ cp $DEPS/lib/libasdcp-libdcp.dylib $WORK/$libs/ cp $DEPS/lib/libkumu-libdcp.dylib $WORK/$libs/ @@@ -58,7 -58,7 +58,7 @@@ cp $ENV/lib/libfontconfig*.dylib $WORK/ cp $ENV/lib/libfreetype*.dylib $WORK/$libs/ cp $ENV/lib/libexpat*.dylib $WORK/$libs/ --for obj in $WORK/$macos/dvdomatic $WORK/$libs/*.dylib; do ++for obj in $WORK/$macos/dcpomatic $WORK/$libs/*.dylib; do deps=`otool -L $obj | awk '{print $1}' | egrep "(/Users/carl|libboost|libssh)"` changes="" for dep in $deps; do @@@ -70,13 -70,13 +70,13 @@@ fi done - + pwd cp build/platform/osx/Info.plist $WORK/$approot --cp icons/dvdomatic.icns $WORK/$resources/DVD-o-matic.icns ++cp icons/dcpomatic.icns $WORK/$resources/DVD-o-matic.icns --tmp_dmg=$WORK/dvdomatic_tmp.dmg --dmg="$WORK/DVD-o-matic $version.dmg" --vol_name=DVD-o-matic-$version ++tmp_dmg=$WORK/dcpomatic_tmp.dmg ++dmg="$WORK/DCP-o-matic $version.dmg" ++vol_name=DCP-o-matic-$version mkdir -p $WORK/$vol_name @@@ -100,8 -100,8 +100,8 @@@ echo set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 64 make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} - set position of item "DVD-o-matic.app" of container window to {90, 100} - set position of item "Applications" of container window to {310, 100} - set position of item "DVD-o-matic.app" of container window to {90, 80} ++ set position of item "DCP-o-matic.app" of container window to {90, 80} + set position of item "Applications" of container window to {310, 80} close open update without registering applications @@@ -117,8 -117,8 +117,8 @@@ syn umount $device hdiutil eject $device hdiutil convert -format UDZO $tmp_dmg -imagekey zlib-level=9 -o "$dmg" --sips -i $WORK/$resources/DVD-o-matic.icns --DeRez -only icns $WORK/$resources/DVD-o-matic.icns > $WORK/$resources/DVD-o-matic.rsrc --Rez -append $WORK/$resources/DVD-o-matic.rsrc -o "$dmg" ++sips -i $WORK/$resources/DCP-o-matic.icns ++DeRez -only icns $WORK/$resources/DCP-o-matic.icns > $WORK/$resources/DCP-o-matic.rsrc ++Rez -append $WORK/$resources/DCP-o-matic.rsrc -o "$dmg" SetFile -a C "$dmg" diff --cc platform/windows/installer.nsi.32.in index 664904767,dbe408564..3a2cdb9e8 --- a/platform/windows/installer.nsi.32.in +++ b/platform/windows/installer.nsi.32.in @@@ -79,14 -79,14 +79,15 @@@ File "%deps%/bin/libpixman-1-0.dll File "%deps%/bin/libfontconfig-1.dll" File "%deps%/bin/libexpat-1.dll" File "%deps%/bin/libbz2.dll" +File "%deps%/bin/cxml.dll" -File "%binaries%/src/wx/dvdomatic-wx.dll" -File "%binaries%/src/lib/dvdomatic.dll" -File "%binaries%/src/tools/dvdomatic.exe" -File "%binaries%/src/tools/dvdomatic_batch.exe" -File "%binaries%/src/tools/makedcp.exe" -File "%binaries%/src/tools/servomatic_cli.exe" -File "%binaries%/src/tools/servomatic_gui.exe" +File "%binaries%/src/wx/dcpomatic-wx.dll" +File "%binaries%/src/lib/dcpomatic.dll" +File "%binaries%/src/tools/dcpomatic.exe" +File "%binaries%/src/tools/dcpomatic_batch.exe" ++File "%binaries%/src/tools/dcpomatic_cli.exe" +File "%binaries%/src/tools/dcpomatic_server_cli.exe" +File "%binaries%/src/tools/dcpomatic_server.exe" # I don't know why, but sometimes it seems that # delegates.xml must be in with the binaries, and @@@ -134,12 -134,12 +135,22 @@@ Section "Uninstall RMDir /r "$INSTDIR\*.*" RMDir "$INSTDIR" ++<<<<<<< HEAD +Delete "$DESKTOP\DCP-o-matic.lnk" +Delete "$DESKTOP\DCP-o-matic batch converter.lnk" +Delete "$DESKTOP\DCP-o-matic encode server.lnk" +Delete "$SMPROGRAMS\DCP-o-matic\*.*" +RmDir "$SMPROGRAMS\DCP-o-matic" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DCP-o-matic" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" ++======= + Delete "$DESKTOP\DVD-o-matic.lnk" + Delete "$DESKTOP\DVD-o-matic batch converter.lnk" + Delete "$DESKTOP\DVD-o-matic encode server.lnk" + Delete "$SMPROGRAMS\DVD-o-matic\*.*" + RmDir "$SMPROGRAMS\DVD-o-matic" + DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DVD-o-matic" + DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" ++>>>>>>> master SectionEnd diff --cc platform/windows/installer.nsi.64.in index fd1237727,7727207d8..f4f1e9068 --- a/platform/windows/installer.nsi.64.in +++ b/platform/windows/installer.nsi.64.in @@@ -89,14 -89,14 +89,15 @@@ File "%deps%/bin/libpixman-1-0.dll File "%deps%/bin/libfontconfig-1.dll" File "%deps%/bin/libexpat-1.dll" File "%deps%/bin/libbz2.dll" +File "%deps%/bin/cxml.dll" -File "%binaries%/src/wx/dvdomatic-wx.dll" -File "%binaries%/src/lib/dvdomatic.dll" -File "%binaries%/src/tools/dvdomatic.exe" -File "%binaries%/src/tools/dvdomatic_batch.exe" -File "%binaries%/src/tools/makedcp.exe" -File "%binaries%/src/tools/servomatic_cli.exe" -File "%binaries%/src/tools/servomatic_gui.exe" +File "%binaries%/src/wx/dcpomatic-wx.dll" +File "%binaries%/src/lib/dcpomatic.dll" +File "%binaries%/src/tools/dcpomatic.exe" +File "%binaries%/src/tools/dcpomatic_batch.exe" ++File "%binaries%/src/tools/dcpomatic_cli.exe" +File "%binaries%/src/tools/dcpomatic_server_cli.exe" +File "%binaries%/src/tools/dcpomatic_server.exe" # I don't know why, but sometimes it seems that # delegates.xml must be in with the binaries, and diff --cc run/dvdomatic-osx index ac42c3186,ac42c3186..000000000 deleted file mode 100755,100755 --- a/run/dvdomatic-osx +++ /dev/null @@@ -1,15 -1,15 +1,0 @@@ --#!/bin/bash -- --export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:build/src/lib:build/src:/Users/carl/Environments/osx/10.8/lib --if [ "$1" == "--debug" ]; then -- shift -- gdb --args build/src/tools/dvdomatic "$*" --elif [ "$1" == "--valgrind" ]; then -- shift -- valgrind --tool="memcheck" build/src/tools/dvdomatic $* --elif [ "$1" == "--i18n" ]; then -- shift -- LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*" --else -- build/src/tools/dvdomatic "$*" --fi diff --cc run/dvdomatic_batch index 7b6ef93ae,7b6ef93ae..000000000 deleted file mode 100755,100755 --- a/run/dvdomatic_batch +++ /dev/null @@@ -1,15 -1,15 +1,0 @@@ --#!/bin/bash -- --export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:$LD_LIBRARY_PATH --if [ "$1" == "--debug" ]; then -- shift -- gdb --args build/src/tools/dvdomatic_batch "$*" --elif [ "$1" == "--valgrind" ]; then -- shift -- valgrind --tool="memcheck" build/src/tools/dvdomatic_batch $* --elif [ "$1" == "--i18n" ]; then -- shift -- LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic_batch "$*" --else -- build/src/tools/dvdomatic_batch --fi diff --cc src/lib/ab_transcode_job.cc index bdde8a405,a204677db..a29e78776 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@@ -20,8 -20,12 +20,9 @@@ #include #include "ab_transcode_job.h" #include "film.h" -#include "format.h" -#include "filter.h" #include "ab_transcoder.h" #include "config.h" -#include "encoder.h" + #include "log.h" #include "i18n.h" diff --cc src/lib/cross.cc index f232f1779,7fbba86f9..ffd44eb02 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@@ -17,21 -17,67 +17,67 @@@ */ + #include + #include #include "cross.h" -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX #include #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS #include "windows.h" #endif -#ifdef DVDOMATIC_OSX ++#ifdef DCPOMATIC_OSX + #include + #endif + + using std::pair; + using std::ifstream; + using std::string; void -dvdomatic_sleep (int s) +dcpomatic_sleep (int s) { -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX sleep (s); #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS Sleep (s * 1000); #endif } + + /** @return A pair containing CPU model name and the number of processors */ + pair + cpu_info () + { + pair info; + info.second = 0; + -#ifdef DVDOMATIC_LINUX ++#ifdef DCPOMATIC_LINUX + ifstream f ("/proc/cpuinfo"); + while (f.good ()) { + string l; + getline (f, l); + if (boost::algorithm::starts_with (l, "model name")) { + string::size_type const c = l.find (':'); + if (c != string::npos) { + info.first = l.substr (c + 2); + } + } else if (boost::algorithm::starts_with (l, "processor")) { + ++info.second; + } + } + #endif + -#ifdef DVDOMATIC_OSX ++#ifdef DCPOMATIC_OSX + size_t N = sizeof (info.second); + sysctlbyname ("hw.ncpu", &info.second, &N, 0, 0); + char buffer[64]; + N = sizeof (buffer); + if (sysctlbyname ("machdep.cpu.brand_string", buffer, &N, 0, 0) == 0) { + info.first = buffer; + } + #endif + + return info; + } + diff --cc src/lib/cross.h index 00457c968,970bf3e9d..d185286b1 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@@ -21,4 -23,5 +21,5 @@@ #define WEXITSTATUS(w) (w) #endif -void dvdomatic_sleep (int); +void dcpomatic_sleep (int); + extern std::pair cpu_info (); diff --cc src/lib/film.cc index ef29d35fd,8aedd7639..75ec700e0 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@@ -46,14 -47,12 +46,15 @@@ #include "config.h" #include "version.h" #include "ui_signaller.h" -#include "video_decoder.h" -#include "audio_decoder.h" -#include "sndfile_decoder.h" #include "analyse_audio_job.h" +#include "playlist.h" +#include "player.h" +#include "ffmpeg_content.h" +#include "imagemagick_content.h" +#include "sndfile_content.h" +#include "dcp_content_type.h" +#include "ratio.h" + #include "cross.h" #include "i18n.h" diff --cc src/lib/imagemagick_content.h index 8ed6b0873,000000000..d7673d870 mode 100644,000000..100644 --- a/src/lib/imagemagick_content.h +++ b/src/lib/imagemagick_content.h @@@ -1,51 -1,0 +1,51 @@@ +/* + Copyright (C) 2013 Carl Hetherington + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 DVDOMATIC_IMAGEMAGICK_CONTENT_H - #define DVDOMATIC_IMAGEMAGICK_CONTENT_H ++#ifndef DCPOMATIC_IMAGEMAGICK_CONTENT_H ++#define DCPOMATIC_IMAGEMAGICK_CONTENT_H + +#include +#include "video_content.h" + +namespace cxml { + class Node; +} + +class ImageMagickContent : public VideoContent +{ +public: + ImageMagickContent (boost::shared_ptr, boost::filesystem::path); + ImageMagickContent (boost::shared_ptr, boost::shared_ptr); + + boost::shared_ptr shared_from_this () { + return boost::dynamic_pointer_cast (Content::shared_from_this ()); + }; + + void examine (boost::shared_ptr); + std::string summary () const; + void as_xml (xmlpp::Node *) const; + boost::shared_ptr clone () const; + Time length () const; + + void set_video_length (ContentVideoFrame); + + static bool valid_file (boost::filesystem::path); +}; + +#endif diff --cc src/lib/player.cc index 757f9bbce,000000000..85b4cbd4f mode 100644,000000..100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@@ -1,383 -1,0 +1,384 @@@ +/* + Copyright (C) 2013 Carl Hetherington + + 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; either version 2 of the License, or + (at your option) any later version. + + 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. + +*/ + ++#include +#include "player.h" +#include "film.h" +#include "ffmpeg_decoder.h" +#include "ffmpeg_content.h" +#include "imagemagick_decoder.h" +#include "imagemagick_content.h" +#include "sndfile_decoder.h" +#include "sndfile_content.h" +#include "playlist.h" +#include "job.h" +#include "image.h" +#include "null_content.h" +#include "black_decoder.h" +#include "silence_decoder.h" + +using std::list; +using std::cout; +using std::min; +using std::max; +using std::vector; +using boost::shared_ptr; +using boost::weak_ptr; +using boost::dynamic_pointer_cast; + +struct Piece +{ + Piece (shared_ptr c, shared_ptr d) + : content (c) + , decoder (d) + {} + + shared_ptr content; + shared_ptr decoder; +}; + +Player::Player (shared_ptr f, shared_ptr p) + : _film (f) + , _playlist (p) + , _video (true) + , _audio (true) + , _subtitles (true) + , _have_valid_pieces (false) + , _position (0) + , _audio_buffers (f->dcp_audio_channels(), 0) + , _next_audio (0) +{ + _playlist->Changed.connect (bind (&Player::playlist_changed, this)); + _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2)); +} + +void +Player::disable_video () +{ + _video = false; +} + +void +Player::disable_audio () +{ + _audio = false; +} + +void +Player::disable_subtitles () +{ + _subtitles = false; +} + +bool +Player::pass () +{ + if (!_have_valid_pieces) { + setup_pieces (); + _have_valid_pieces = true; + } + + /* Here we are just finding the active decoder with the earliest last emission time, then + calling pass on it. + */ + + Time earliest_t = TIME_MAX; + shared_ptr earliest; + + for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { + cout << "check " << (*i)->content->file() + << " start=" << (*i)->content->start() + << ", next=" << (*i)->decoder->next() + << ", end=" << (*i)->content->end() << "\n"; + + if ((*i)->decoder->done ()) { + continue; + } + + if (!_audio && dynamic_pointer_cast ((*i)->decoder) && !dynamic_pointer_cast ((*i)->decoder)) { + continue; + } + + Time const t = (*i)->content->start() + (*i)->decoder->next(); + if (t < earliest_t) { + cout << "\t candidate; " << t << " " << (t / TIME_HZ) << ".\n"; + earliest_t = t; + earliest = *i; + } + } + + if (!earliest) { + flush (); + return true; + } + + cout << "PASS:\n"; + cout << "\tpass " << earliest->content->file() << " "; + if (dynamic_pointer_cast (earliest->content)) { + cout << " FFmpeg.\n"; + } else if (dynamic_pointer_cast (earliest->content)) { + cout << " ImageMagickContent.\n"; + } else if (dynamic_pointer_cast (earliest->content)) { + cout << " SndfileContent.\n"; + } else if (dynamic_pointer_cast (earliest->decoder)) { + cout << " Black.\n"; + } else if (dynamic_pointer_cast (earliest->decoder)) { + cout << " Silence.\n"; + } + + earliest->decoder->pass (); + _position = earliest->content->start() + earliest->decoder->next (); + cout << "\tpassed to " << _position << " " << (_position / TIME_HZ) << "\n"; + + return false; +} + +void +Player::process_video (weak_ptr weak_content, shared_ptr image, bool same, Time time) +{ + shared_ptr content = weak_content.lock (); + if (!content) { + return; + } + + time += content->start (); + + Video (image, same, time); +} + +void +Player::process_audio (weak_ptr weak_content, shared_ptr audio, Time time) +{ + shared_ptr content = weak_content.lock (); + if (!content) { + return; + } + + /* The time of this audio may indicate that some of our buffered audio is not going to + be added to any more, so it can be emitted. + */ + + time += content->start (); + + if (time > _next_audio) { + /* We can emit some audio from our buffers */ + OutputAudioFrame const N = _film->time_to_audio_frames (time - _next_audio); + assert (N <= _audio_buffers.frames()); + shared_ptr emit (new AudioBuffers (_audio_buffers.channels(), N)); + emit->copy_from (&_audio_buffers, N, 0, 0); + Audio (emit, _next_audio); + _next_audio += _film->audio_frames_to_time (N); + + /* And remove it from our buffers */ + if (_audio_buffers.frames() > N) { + _audio_buffers.move (N, 0, _audio_buffers.frames() - N); + } + _audio_buffers.set_frames (_audio_buffers.frames() - N); + } + + /* Now accumulate the new audio into our buffers */ + _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames()); + _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ()); + _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames()); +} + +void +Player::flush () +{ + if (_audio_buffers.frames() > 0) { + shared_ptr emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames())); + emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0); + Audio (emit, _next_audio); + _next_audio += _film->audio_frames_to_time (_audio_buffers.frames ()); + _audio_buffers.set_frames (0); + } +} + +/** @return true on error */ +void +Player::seek (Time t) +{ + if (!_have_valid_pieces) { + setup_pieces (); + _have_valid_pieces = true; + } + + if (_pieces.empty ()) { + return; + } + +// cout << "seek to " << t << " " << (t / TIME_HZ) << "\n"; + + for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { + Time s = t - (*i)->content->start (); + s = max (static_cast