예제 #1
0
파일: TrackIO.cpp 프로젝트: Barrett17/Faber
AudioTrack*
TrackIO::ImportAudio(BMediaFile* mediaFile, const char* name)
{
	TrackIndex* index = new TrackIndex();

	media_format format;

	MediaFormatBuilder::BuildAudioBlockRawFormat(&format);

	// TODO check original file format to ask 
	// if the user want it to be resampled or not.
	// NOTE atm we are considering only the first track, may and probably will
	// change in future, or at least the user should be able to select which track
	// to import (eventually all and as separated track).
	BMediaTrack* track = mediaFile->TrackAt(0);
	if (track->DecodedFormat(&format) != B_OK) {
		// Critical error show a popup
		return NULL;
	}

	uint32 channels = format.u.raw_audio.channel_count;
	for (uint32 i = 0; i < channels; i++) {
		MediaBlockMap* channel = new MediaBlockMap();
		index->AddChannel(channel);
	}

	WindowsManager::ProgressUpdate(10.0f, "Loading audio data");

	int64 frames = 0;

	int64 bufferFrames = (format.u.raw_audio.buffer_size
		/ (format.u.raw_audio.format 
		& media_raw_audio_format::B_AUDIO_SIZE_MASK));

	float buffer[bufferFrames];

	memset(&buffer, 0, format.u.raw_audio.buffer_size);
	while (track->ReadFrames(buffer, &frames) == B_OK) {
		_BuildBlocks((float*)buffer, frames*channels, index,
			channels);
		memset(&buffer, 0, format.u.raw_audio.buffer_size);
	}

	WindowsManager::ProgressUpdate(50.0f, "Flushing data and preview");

	mediaFile->ReleaseTrack(track);

	// This is done to optimize writes, the data is cached in a buffer
	// and then written to the BPositionIO.
	for (uint32 j = 0; j < index->CountChannels(); j++)
		index->ChannelAt(j)->Writer()->Flush();

	return new AudioTrack(name, index);
}
예제 #2
0
status_t
MainView::LoadWave(const entry_ref& ref)
{
	bigtime_t startLoadWave = system_time();

	fDestCursor = 0;
	fSourceCursor = 0;
	fAverage = 0.0f;
	fAverageCursor = 0;
	fDownsamplingWidth = 0;
	fDownsampleCount = 0;

	// instantiate a BMediaFile object, and make sure there was no error.
	/*BEntry entry("./song.wav");
	entry_ref ref;
	entry.GetRef(&ref);*/
	BMediaFile* mediaFile = new BMediaFile(&ref);
	status_t err = mediaFile->InitCheck();
	if (err != B_OK) {
		printf("cannot contruct BMediaFile object -- %s\n", strerror(err));
		return err;
	}

	for (int32 i = 0; i < mediaFile->CountTracks(); i++) {
		BMediaTrack* track = mediaFile->TrackAt(i);
		if (track == NULL) {
			printf("cannot contruct BMediaTrack object\n");
			return B_ERROR;
		}

		media_format format;
		format.type = B_MEDIA_RAW_AUDIO;
		format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
		err = track->DecodedFormat(&format);
		if (err != B_OK) {
			printf("BMediaTrack::DecodedFormat error -- %s\n", strerror(err));
			return err;
		}

		if (format.type == B_MEDIA_RAW_AUDIO) {

			// get the actual sourceWindow.left obtained by seeking
			bigtime_t start = system_time();
			int64 actualSeekFrame = fSourceWindow.left;
			err = track->SeekToFrame(&actualSeekFrame);
			if (err != B_OK) {
				printf("BMediaTrack::SeekToFrame(%lli) error -- %s\n", fSourceWindow.left, strerror(err));
				return err;
			}
			printf("BMediaTrack::SeekToFrame(%lli) seekedto=%lli in %llims\n", fSourceWindow.left, actualSeekFrame, (system_time() - start) / 1000);
			fSourceWindow.left = actualSeekFrame;

			frame_range destWindow(0, (uint64) fWaveFrame.Width());
			int64 totalSourceFrameCount = track->CountFrames();
			fDownsamplingWidth = fSourceWindow.Width() / destWindow.Width();

			printf("Source window left=%lli right=%lli width=%lli (total=%lli)\n", fSourceWindow.left, fSourceWindow.right, fSourceWindow.Width(), totalSourceFrameCount);
			printf("Dest window left=%lli right=%lli width=%lli\n", destWindow.left, destWindow.right, destWindow.Width());
			printf("Downsampling width=%lli\n", fDownsamplingWidth);

			delete [] fWave;
			fWave = NULL;
			fWave = new(std::nothrow) float[fSourceWindow.Width() / fDownsamplingWidth]; // ATT: on en prend plus que la largeur de dest car downsampling width entier
			if (fWave == NULL)
				return B_NO_MEMORY;

			char* buffer = new(std::nothrow) char[format.u.raw_audio.buffer_size];
			if (buffer == NULL)
				return B_NO_MEMORY;

			int64 readFrameCount = 0;
			media_header mediaHeader;
			fSourceCursor = fSourceWindow.left;
			for(int64 j = 0; j < fSourceWindow.Width(); j += readFrameCount) {

				err = track->ReadFrames(buffer, &readFrameCount, &mediaHeader);
				if (err) {
					printf("BMediaTrack::ReadFrames error -- %s\n", strerror(err));
					delete [] buffer;
					break;
					// TODO fatal error?
				}

				if (fSourceCursor + readFrameCount >= fSourceWindow.right) {
					readFrameCount = fSourceWindow.right - fSourceCursor;
					printf("yes readFrameCount = %lli\n", readFrameCount);
				}

				_ProcessAudio(buffer, &format, readFrameCount);
			}
			printf("Source cursor %li (read %li)\n", fSourceCursor, fSourceCursor - fSourceWindow.left);
			printf("Dest cursor %li\n", fDestCursor);

			delete [] buffer;
		}

		mediaFile->ReleaseTrack(track);
	}
	delete mediaFile;


	printf("LoadWave in %lims\n", (system_time() - startLoadWave) / 1000 );
	fCurrentEntryRef = ref;
	return B_OK;
}
예제 #3
0
int32
MediaView::MediaPlayer(
	void	*arg)
{
	MediaView*		view = (MediaView *)arg;
	BWindow*		window = view->Window();
	BBitmap*		bitmap = view->fBitmap;
	BMediaTrack*	videoTrack = view->fVideoTrack;
	BMediaTrack*	audioTrack = view->fAudioTrack;
	BMediaTrack*	counterTrack = (videoTrack != NULL) ? videoTrack : audioTrack;
	AudioOutput*	audioOutput = view->fAudioOutput;
	void*			adBuffer = view->fAudioDumpingBuffer;
	int64			numFrames = counterTrack->CountFrames();
	int64			numFramesToSkip = 0;
	int64			numSkippedFrames = 0;
	bool			scrubbing = false;
	bool			seekNeeded = false;
	int64			dummy;
	media_header	mh;
	bigtime_t		vStartTime, aStartTime, seekTime, snoozeTime, startTime;
	bigtime_t		curScrubbing, lastScrubbing, lastTime;

	curScrubbing = lastScrubbing = system_time();
	seekTime = 0LL;

	// Main processing loop (handle stop->start->stop)
	while (acquire_sem(view->fPlaySem) == B_OK) {
		release_sem(view->fPlaySem);
		
		// as we are doing stop->start, restart audio if needed.
		if (audioTrack != NULL)
			audioOutput->Play();
		startTime = system_time()-counterTrack->CurrentTime();		

		// This will loop until the end of the stream
		while ((counterTrack->CurrentFrame() < numFrames) || scrubbing) {
		
			// We are in scrub mode
			if (acquire_sem(view->fScrubSem) == B_OK) {
				curScrubbing = system_time();

				// We are entering scrub mode
				if (!scrubbing) {
					if (audioTrack != NULL)
						audioOutput->Stop();
					scrubbing = true;
				}
				// Do a seek.
				seekNeeded = true;
				seekTime = view->fScrubTime;
			}
			// We are not scrubbing
			else if (scrubbing) {
				if (audioTrack != NULL)
					audioOutput->Play();
				scrubbing = false;
			}
			
			// Handle seeking
			if (seekNeeded) {
				if (videoTrack) {
					// Seek the seekTime as close as possible
					vStartTime = seekTime;
					videoTrack->SeekToTime(&vStartTime);
					
					// Read frames until we get less than 50ms ahead.
					lastTime = vStartTime;
					do {
						bitmap->LockBits();
						status_t err = videoTrack->ReadFrames((char*)bitmap->Bits(), &dummy, &mh);
						bitmap->UnlockBits();
						if (err != B_OK) break;
						vStartTime = mh.start_time;
						if ((dummy == 0) || (vStartTime <= lastTime))
							break;
						lastTime = vStartTime;
					} while (seekTime - vStartTime > 50000);
				}
				
				if (audioTrack) {
					// Seek the extractor as close as possible
					aStartTime = seekTime;
					audioOutput->SeekToTime(&aStartTime);
					
					// Read frames until we get less than 50ms ahead.
					lastTime = aStartTime;
					while (seekTime - aStartTime > 50000) {
						if (audioTrack->ReadFrames((char *)adBuffer, &dummy, &mh) != B_OK)
							break;
						aStartTime = mh.start_time;
						if ((dummy == 0) || (aStartTime <= lastTime))
							break;
						lastTime = aStartTime;
					}
				}
				else startTime = system_time() - vStartTime;
				
				// Set the current time
				view->fCurTime = seekTime;	
			
				seekNeeded = false;
			}		
			// Handle normal playing mode
			else {
				// Get the next video frame, if any
				if (videoTrack != NULL) {
					bitmap->LockBits();
					status_t err = videoTrack->ReadFrames((char*)bitmap->Bits(), &dummy, &mh);
					bitmap->UnlockBits();
					if (err != B_OK) goto do_reset;
					if (dummy == 0)
						goto do_reset;
					vStartTime = mh.start_time;
				}

				// Estimated snoozeTime
				if (audioTrack != NULL)
					startTime = audioOutput->TrackTimebase();
				if (videoTrack != NULL)
					snoozeTime = vStartTime - (system_time() - startTime);
				else
					snoozeTime = 25000;

				// Handle timing issues
				if (snoozeTime > 5000LL) {
					view->fSnoozing = true;
					snooze(snoozeTime-1000);
					view->fSnoozing = false;
				}
				else if (snoozeTime < -5000) {
					numSkippedFrames++;
					numFramesToSkip++;
				}
				
				// Set the current time
				if (!scrubbing) {
					view->fCurTime = system_time() - startTime;
					if (view->fCurTime < seekTime)
						view->fCurTime = seekTime;
				}				
			}
				
			// Handle the drawing : no drawing if we need to skip a frame...
			if (numSkippedFrames > 0)
				numSkippedFrames--;
			// If we can't lock the window after 50ms, better to give up for
			// that frame...
			else if (window->LockWithTimeout(50000) == B_OK) {
				if ((videoTrack != NULL) && !view->fUsingOverlay)
					view->DrawBitmap(bitmap, view->VideoBounds());
				view->fMediaBar->SetCurTime(view->fCurTime);
				window->Unlock();
				// In scrub mode, don't scrub more than 10 times a second
				if (scrubbing) {
					snoozeTime = (100000LL+lastScrubbing) - system_time();
					if (snoozeTime > 4000LL) {
						view->fSnoozing = true;
						snooze(snoozeTime-1000LL);
						view->fSnoozing = false;
					}
					lastScrubbing = curScrubbing;
				}
			}				
			
			// Check if we are required to stop.
			if (acquire_sem_etc(view->fPlaySem, 1, B_TIMEOUT, 0) == B_OK)
				release_sem(view->fPlaySem);
			// The MediaView asked us to stop.
			else {
				if (audioTrack != NULL)
					audioOutput->Stop();
				goto do_restart;
			}
DEBUG("############ Current frame:%Ld, total frame:%Ld\n", counterTrack->CurrentFrame(), numFrames);
		}		

		// If we exited the main streaming loop because we are at the end,
		// then we need to loop.
		if (counterTrack->CurrentFrame() >= numFrames) {
do_reset:
			if (audioTrack != NULL)
				audioOutput->Stop();
				
			seekNeeded = true;
			seekTime = 0LL;
			scrubbing = true;
		}
do_restart:;
	}

	return (B_NO_ERROR);
}
int
main(int argc, char *argv[])
{
	// 256 frames * 4 buffer parts * 2 channels * 2 bytes per sample
	// will give us internal buffer of 4096 bytes
	size_t framesPerBufferPart = 256;
	size_t bufferPartCount = 4;

	if (argc != 2 && argc != 4) {
		printf("Usage: %s <sound file name> [<frames per part> <parts>]\n",
			argv[0]);
		return 0;
	}

	if (argc == 4) {
		size_t size = strtoul(argv[2], NULL, 10);
		if (size > 0)
			framesPerBufferPart = size;

		size = strtoul(argv[3], NULL,  10);
		if (size == 1) {
			printf("at least 2 buffer parts are needed\n");
			return 1;
		}
		if (size > 0)
			bufferPartCount = size;
	}

	printf("frames per buffer part: %ld\n", framesPerBufferPart);
	printf("buffer part count: %ld\n", bufferPartCount);

	BEntry entry(argv[1]);
	if (entry.InitCheck() != B_OK || !entry.Exists()) {
		printf("cannot open input file\n");
		return 1;
	}

	entry_ref entryRef;
	entry.GetRef(&entryRef);

	BMediaFile mediaFile(&entryRef);
	if (mediaFile.InitCheck() != B_OK) {
		printf("file not supported\n");
		return 1;
	}

	if (mediaFile.CountTracks() == 0) {
		printf("no tracks found in file\n");
		return 1;
	}

	BMediaTrack *mediaTrack = mediaFile.TrackAt(0);
	if (mediaTrack == NULL) {
		printf("problem getting track from file\n");
		return 1;
	}

	// propose format, let it decide frame rate, channels number and buf size
	media_format format;
	memset(&format, 0, sizeof(format));
	format.type = B_MEDIA_RAW_AUDIO;
	format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
	format.u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN;

	if (mediaTrack->DecodedFormat(&format) != B_OK) {
		printf("cannot set decoder output format\n");
		return 1;
	}

	printf("negotiated format:\n");
	printf("frame rate: %g Hz\n", format.u.raw_audio.frame_rate);
	printf("channel count: %ld\n", format.u.raw_audio.channel_count);
	printf("buffer size: %ld bytes\n", format.u.raw_audio.buffer_size);

	gs_audio_format gsFormat;
	memset(&gsFormat, 0, sizeof(gsFormat));
	gsFormat.frame_rate = format.u.raw_audio.frame_rate;
	gsFormat.channel_count = format.u.raw_audio.channel_count;
	gsFormat.format = format.u.raw_audio.format;
	gsFormat.byte_order = format.u.raw_audio.byte_order;

	BPushGameSound pushGameSound(framesPerBufferPart, &gsFormat,
		bufferPartCount);
	if (pushGameSound.InitCheck() != B_OK) {
		printf("trouble initializing push game sound: %s\n",
			strerror(pushGameSound.InitCheck()));
		return 1;
	}

	uint8 *buffer;
	size_t bufferSize;
	if (pushGameSound.LockForCyclic((void **)&buffer, &bufferSize)
			!= BPushGameSound::lock_ok) {
		printf("cannot lock buffer\n");
		return 1;
	}
	memset(buffer, 0, bufferSize);

	if (pushGameSound.StartPlaying() != B_OK) {
		printf("cannot start playback\n");
		return 1;
	}

	printf("playing, press [esc] to exit...\n");

	uint8 decoded[format.u.raw_audio.buffer_size * 2];
	size_t bufferPartSize = framesPerBufferPart
		* format.u.raw_audio.channel_count
		* (format.u.raw_audio.format
			& media_raw_audio_format::B_AUDIO_SIZE_MASK);
	size_t decodedSize = 0;
	size_t partPos = 0;
	size_t pos = 0; /*pushGameSound.CurrentPosition();*/
	key_info keyInfo;

	while (true) {
		// fill buffer part with data from decoded buffer
		while (partPos < bufferPartSize && decodedSize) {
			size_t size = min_c(bufferPartSize - partPos, decodedSize);

			memcpy(buffer + pos + partPos, decoded, size);
			partPos += size;

			decodedSize -= size;
			memmove(decoded, decoded + size, decodedSize);
		}

		// if there are too little data to fill next buffer part
		// read next decoded frames
		if (partPos < bufferPartSize) {
			int64 frameCount;
			if (mediaTrack->ReadFrames(decoded + decodedSize, &frameCount)
					!= B_OK)
				break;
			if (frameCount == 0)
				break;

			decodedSize += frameCount * format.u.raw_audio.channel_count
				* (format.u.raw_audio.format
					& media_raw_audio_format::B_AUDIO_SIZE_MASK);

			printf("\rtime: %.2f",
				(double)mediaTrack->CurrentTime() / 1000000LL);
			fflush(stdout);

			continue;
		}

		// this buffer part is done
		partPos = 0;
		pos += bufferPartSize;
		if (bufferSize <= pos)
			pos = 0;

		// playback sync - wait for the buffer part we're about to fill to be
		// played
		while (pushGameSound.CurrentPosition() >= pos + bufferPartSize
			|| pushGameSound.CurrentPosition() < pos)
			snooze(1000 * framesPerBufferPart / gsFormat.frame_rate);

		// check escape key state
		if (get_key_info(&keyInfo) != B_OK) {
			printf("\nkeyboard state read error\n");
			break;
		}
		if ((keyInfo.key_states[0] & 0x40) != 0)
			break;
	}

	pushGameSound.StopPlaying();

	mediaFile.ReleaseTrack(mediaTrack);
	mediaFile.CloseFile();

	printf("\nfinished.\n");

	return 0;
}
status_t
MediaConverterApp::_ConvertFile(BMediaFile* inFile, BMediaFile* outFile,
	media_codec_info* audioCodec, media_codec_info* videoCodec,
	int32 audioQuality, int32 videoQuality,
	bigtime_t startDuration, bigtime_t endDuration)
{
	BMediaTrack* inVidTrack = NULL;
	BMediaTrack* inAudTrack = NULL;
	BMediaTrack* outVidTrack = NULL;
	BMediaTrack* outAudTrack = NULL;

	media_format inFormat;
	media_format outAudFormat;
	media_format outVidFormat;

	media_raw_audio_format* raf = NULL;
	media_raw_video_format* rvf = NULL;

	int32 width = -1;
	int32 height = -1;

	uint8* videoBuffer = NULL;
	uint8* audioBuffer = NULL;

	// gather the necessary format information and construct output tracks
	int64 videoFrameCount = 0;
	int64 audioFrameCount = 0;

	status_t ret = B_OK;

	int32 tracks = inFile->CountTracks();
	for (int32 i = 0; i < tracks && (!outAudTrack || !outVidTrack); i++) {
		BMediaTrack* inTrack = inFile->TrackAt(i);
		memset(&inFormat, 0, sizeof(media_format));
		inTrack->EncodedFormat(&inFormat);
		if (inFormat.IsAudio() && (audioCodec != NULL)) {
			inAudTrack = inTrack;
			memset(&outAudFormat, 0, sizeof(media_format));
			outAudFormat.type = B_MEDIA_RAW_AUDIO;
			raf = &(outAudFormat.u.raw_audio);
			inTrack->DecodedFormat(&outAudFormat);

			audioBuffer = new uint8[raf->buffer_size];
//			audioFrameSize = (raf->format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
//			audioFrameSize = (raf->format & 0xf) * raf->channel_count;
			outAudTrack = outFile->CreateTrack(&outAudFormat, audioCodec);

			if (outAudTrack != NULL) {
				if (outAudTrack->SetQuality(audioQuality / 100.0f) != B_OK
					&& fWin->Lock()) {
					fWin->SetAudioQualityLabel(
						B_TRANSLATE("Audio quality not supported"));
					fWin->Unlock();
				}
			}

		} else if (inFormat.IsVideo() && (videoCodec != NULL)) {
			inVidTrack = inTrack;
			width = (int32)inFormat.Width();
			height = (int32)inFormat.Height();

			// construct desired decoded video format
			memset(&outVidFormat, 0, sizeof(outVidFormat));
			outVidFormat.type = B_MEDIA_RAW_VIDEO;
			rvf = &(outVidFormat.u.raw_video);
			rvf->last_active = (uint32)(height - 1);
			rvf->orientation = B_VIDEO_TOP_LEFT_RIGHT;
			rvf->display.format = B_RGB32;
			rvf->display.bytes_per_row = 4 * width;
			rvf->display.line_width = width;
			rvf->display.line_count = height;

			inVidTrack->DecodedFormat(&outVidFormat);

			if (rvf->display.format == B_RGBA32) {
				printf("fixing color space (B_RGBA32 -> B_RGB32)");
				rvf->display.format = B_RGB32;
			}
			// Transfer the display aspect ratio.
			if (inFormat.type == B_MEDIA_ENCODED_VIDEO) {
				rvf->pixel_width_aspect
					= inFormat.u.encoded_video.output.pixel_width_aspect;
				rvf->pixel_height_aspect
					= inFormat.u.encoded_video.output.pixel_height_aspect;
			} else {
				rvf->pixel_width_aspect
					= inFormat.u.raw_video.pixel_width_aspect;
				rvf->pixel_height_aspect
					= inFormat.u.raw_video.pixel_height_aspect;
			}

			videoBuffer = new (std::nothrow) uint8[height
				* rvf->display.bytes_per_row];
			outVidTrack = outFile->CreateTrack(&outVidFormat, videoCodec);

			if (outVidTrack != NULL) {
				// DLM Added to use 3ivx Parameter View
				const char* videoQualitySupport = NULL;
				BView* encoderView = outVidTrack->GetParameterView();
				if (encoderView) {
					MediaEncoderWindow* encoderWin
						= new MediaEncoderWindow(BRect(50, 50, 520, 555),
							encoderView);
					encoderWin->Go();
						// blocks until the window is quit

					// The quality setting is ignored by the 3ivx encoder if the
					// view was displayed, but this method is the trigger to read
					// all the parameter settings
					outVidTrack->SetQuality(videoQuality / 100.0f);

					// We can now delete the encoderView created for us by the encoder
					delete encoderView;
					encoderView = NULL;

					videoQualitySupport = 
						B_TRANSLATE("Video using parameters form settings");
				} else {
					if (outVidTrack->SetQuality(videoQuality / 100.0f) >= B_OK)
						videoQualitySupport = 
							B_TRANSLATE("Video quality not supported");
				}
				if (videoQualitySupport && fWin->Lock()) {
					fWin->SetVideoQualityLabel(videoQualitySupport);
					fWin->Unlock();
				}
			}
		} else {
			//  didn't do anything with the track
			inFile->ReleaseTrack(inTrack);
		}
	}

	if (!outVidTrack && !outAudTrack) {
		printf("MediaConverterApp::_ConvertFile() - no tracks found!\n");
		ret = B_ERROR;
	}

	if (fCancel) {
		// don't have any video or audio tracks here, or cancelled
		printf("MediaConverterApp::_ConvertFile()"
				" - user canceled before transcoding\n");
		ret = B_CANCELED;
	}

	if (ret < B_OK) {
		delete[] audioBuffer;
		delete[] videoBuffer;
		delete outFile;
		return ret;
	}

	outFile->CommitHeader();
	// this is where you would call outFile->AddCopyright(...)

	int64 framesRead;
	media_header mh;
	int32 lastPercent, currPercent;
	float completePercent;
	BString status;

	int64 start;
	int64 end;
	int32 stat = 0;

	// read video from source and write to destination, if necessary
	if (outVidTrack != NULL) {
		lastPercent = -1;
		videoFrameCount = inVidTrack->CountFrames();
		if (endDuration == 0 || endDuration < startDuration) {
			start = 0;
			end = videoFrameCount;
		} else {
			inVidTrack->SeekToTime(&endDuration, stat);
			end = inVidTrack->CurrentFrame();
			inVidTrack->SeekToTime(&startDuration, stat);
			start = inVidTrack->CurrentFrame();
			if (end > videoFrameCount)
				end =  videoFrameCount;
			if (start > end)
				start = 0;
		}

		framesRead = 0;
		for (int64 i = start; (i <= end) && !fCancel; i += framesRead) {
			if ((ret = inVidTrack->ReadFrames(videoBuffer, &framesRead,
					&mh)) != B_OK) {
				fprintf(stderr, "Error reading video frame %" B_PRId64 ": %s\n", i,
						strerror(ret));
				snprintf(status.LockBuffer(128), 128,
						B_TRANSLATE("Error read video frame %" B_PRId64), i);
				status.UnlockBuffer();
				SetStatusMessage(status.String());

				break;
			}

			if ((ret = outVidTrack->WriteFrames(videoBuffer, framesRead,
					mh.u.encoded_video.field_flags)) != B_OK) {
				fprintf(stderr, "Error writing video frame %" B_PRId64 ": %s\n", i,
						strerror(ret));
				snprintf(status.LockBuffer(128), 128,
						B_TRANSLATE("Error writing video frame %" B_PRId64), i);
				status.UnlockBuffer();
				SetStatusMessage(status.String());

				break;
			}
			completePercent = (float)(i - start) / (float)(end - start) * 100;
			currPercent = (int32)completePercent;
			if (currPercent > lastPercent) {
				lastPercent = currPercent;
				snprintf(status.LockBuffer(128), 128,
					B_TRANSLATE("Writing video track: %" B_PRId32 "%% complete"),
					currPercent);
				status.UnlockBuffer();
				SetStatusMessage(status.String());

			}
		}
		outVidTrack->Flush();
		inFile->ReleaseTrack(inVidTrack);
	}

	// read audio from source and write to destination, if necessary
	if (outAudTrack != NULL) {
		lastPercent = -1;

		audioFrameCount =  inAudTrack->CountFrames();

		if (endDuration == 0 || endDuration < startDuration) {
			start = 0;
			end = audioFrameCount;
		} else {
			inAudTrack->SeekToTime(&endDuration, stat);
			end = inAudTrack->CurrentFrame();
			inAudTrack->SeekToTime(&startDuration, stat);
			start = inAudTrack->CurrentFrame();
			if (end > audioFrameCount)
				end = audioFrameCount;
			if (start > end)
				start = 0;
		}

		for (int64 i = start; (i <= end) && !fCancel; i += framesRead) {
			if ((ret = inAudTrack->ReadFrames(audioBuffer, &framesRead,
				&mh)) != B_OK) {
				fprintf(stderr, "Error reading audio frames: %s\n", strerror(ret));
				snprintf(status.LockBuffer(128), 128,
					B_TRANSLATE("Error read audio frame %" B_PRId64), i);
				status.UnlockBuffer();
				SetStatusMessage(status.String());

				break;
			}

			if ((ret = outAudTrack->WriteFrames(audioBuffer,
				framesRead)) != B_OK) {
				fprintf(stderr, "Error writing audio frames: %s\n",	strerror(ret));
				snprintf(status.LockBuffer(128), 128,
					B_TRANSLATE("Error writing audio frame %" B_PRId64), i);
				status.UnlockBuffer();
				SetStatusMessage(status.String());

				break;
			}
			completePercent = (float)(i - start) / (float)(end - start) * 100;
			currPercent = (int32)completePercent;
			if (currPercent > lastPercent) {
				lastPercent = currPercent;
				snprintf(status.LockBuffer(128), 128,
					B_TRANSLATE("Writing audio track: %" B_PRId32 "%% complete"),
					currPercent);
				status.UnlockBuffer();
				SetStatusMessage(status.String());
			}
		}
		outAudTrack->Flush();
		inFile->ReleaseTrack(inAudTrack);

	}

	outFile->CloseFile();
	delete outFile;

	delete[] videoBuffer;
	delete[] audioBuffer;

	return ret;
}