NeroBurnAtOnce produces dvd disks not readable on dvd player

vbimport

#1

Hello

I have been trying to create a program to burn dynamically-generated DVD Video using the Nero SDK function NeroBurnAtOnce.
I hope to dynamically author DVD video captured from a capture card, and burn to the DVD as each segment is captured and authored.
The capture and authoring part of the system is working well, but I am having significant problems getting NeroBurnAtOnce to burn DVD-compatible disks.

I can burn a disk, which will work in WinDVD on my computer, but does not work when I try to play it in a standard DVD player (A Sanyo).
I can burn exactly the same files using NeroBurn(), and it works. If I copy the data back off the 2 DVD disks and compare them, the files are identical, so it’s not a problem with the data being written - it is something to do with what NeroBurnAtOnce does during the burn.
Note that I am not doing any dynamic authoring in this test version - I am simply trying to burn pre-existing DVD files using NeroBurnAtOnce.

I did some investigation of the disk contents using ISOBuster. I found that the ISO track structure was completely different, and clearly wrong in the BAO version.
Here is a screen grab from ISOBuster of the disk created using NeroBurn() (which works):

Now compare that to the disk created using NeroBurnAtOnce(). Note that there are 3 tracks instead of one, and that the track list shows totally bogus info - everything is in track 1, in both disks, but on the NeroBurnAtOnce() disk, ISOBuster shows that track 1 has a size of about 1.1MB:

So, my question is, what is wrong with my use of NeroBurnAtOnce? As far as I can see, I’m using it correctly. I create a IFileSystemDescContainer object, and fill it with the DVD contents, then I call NeroBurnAtOnce.

The main part of my program is below. I have left out the Nero Callback functions, which about double the size of the program. However, a zip of the full source code of the test app is available here.

I am using:
NeroSDK version v7.0.5.6
MSVC V6 with appropriate service packs
Windows XP sp2

The Nero software info from Nero InfoTool 4.03 is at the bottom of this post, below the code.

I hope someone can explain what I’m doing wrong. I can find no reference to NeroBurnAtOnce() anywhere on CDFreaks, so maybe it just doesn’t work?

Thanks in advance
Michael Potter

// baotest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "NeroAPIGlue.h"
#include "NeroBurnAtOnce.h"
#include "NeroFileSystemContent.h"

using namespace FileSystemContent;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

// member vars
CString m_sDriveLetter;
CString m_sRootPath;
int m_iBurnResult;

FileSystemContent::IFileSystemDescContainer *m_pContainer;
NERO_WRITE_BURN_AT_ONCE *m_pBurnAtOnce;

NERO_DEVICEHANDLE m_hDevice;
NERO_SCSI_DEVICE_INFOS *m_pNeroDeviceInfo;
NERO_CD_INFO *m_pNeroCDInfo;
#define DUMMY_USER_DATA &NeroSettings 	/* &NeroSettings as user data is only used as illustration */

BOOL	m_bAborted;

void DeAllocate();

// function declarations
static void NeroError (char *action); /* display Nero error and exit */

/* for the settings */
static BOOL NERO_CALLBACK_ATTR IdleCallback (void *pUserData);
static NeroUserDlgInOut NERO_CALLBACK_ATTR UserDialog (void *pUserData, NeroUserDlgInOut type, void *data);

/* for the progress display */
static BOOL NERO_CALLBACK_ATTR ProgressCallback (void *pUserData, DWORD dwProgressInPercent);
static BOOL NERO_CALLBACK_ATTR AbortedCallback (void *pUserData);
static void NERO_CALLBACK_ATTR AddLogLine (void *pUserData, NERO_TEXT_TYPE type, const char *text);
static void NERO_CALLBACK_ATTR SetPhaseCallback (void *pUserData, const char *text);
static void NERO_CALLBACK_ATTR DisableAbortCallback (void *pUserData,BOOL abortEnabled);
static void NERO_CALLBACK_ATTR SetMajorPhaseCallback(void *pUserData,NERO_MAJOR_PHASE phase,void *reserved);

/* IO callbacks - both take a FILE * as user data */
static DWORD NERO_CALLBACK_ATTR WriteIOCallback (void *pUserData, BYTE *pBuffer, DWORD dwLen);
static DWORD NERO_CALLBACK_ATTR ReadIOCallback (void *pUserData, BYTE *pBuffer, DWORD dwLen);
static BOOL NERO_CALLBACK_ATTR EOFCallback (void *pUserData);
static BOOL NERO_CALLBACK_ATTR ErrorCallback (void *pUserData);

// dvd file system functions
CString GetLastNeroError();			// name it this way to avoid confusion with the win32 function of the same name

typedef struct
{
	char input;
	NeroUserDlgInOut result;
} Input2DlgOut;

#define DUMMY_USER_DATA &NeroSettings 	/* &NeroSettings as user data is only used as illustration */
NERO_SETTINGS NeroSettings =
{
	"NeroFiles",                    /* look for DLLs in sub directory */
	NULL,NULL,
	"Nero.txt",
	{ IdleCallback, DUMMY_USER_DATA },
	{ UserDialog, DUMMY_USER_DATA }
};

NERO_PROGRESS NeroProgress =
{
	ProgressCallback,
	AbortedCallback,
	AddLogLine,
	SetPhaseCallback,
	DUMMY_USER_DATA,
	DisableAbortCallback,
	SetMajorPhaseCallback
};

// CTRL-C handling => remember and return TRUE in IdleCallback to make API abort

static void __cdecl SigCtrlC (int sig)
{
	m_bAborted = TRUE;
}

bool InitNero();
bool OpenDevice(LPCTSTR pszDriveName);
void BurnDVD();

/* free resources and exit */
static void Exit (int ret)
{
	DeAllocate();

	/* all of these functions may be called even if NeroAPIGlueInit() failed. */
	NeroCloseDevice (m_hDevice);
	NeroFreeMem (m_pNeroDeviceInfo);
	NeroFreeMem (m_pNeroCDInfo);
	NeroClearErrors ();
	NeroDone ();

	NeroAPIGlueDone();

	puts ("
press RETURN to exit");
	getchar ();
	exit (ret);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		nRetCode = 1;
	}
	else
	{
		HRESULT hr = CoInitialize(NULL);

		// here are the parameters - normally, we would pass these in
		m_sDriveLetter	= _T("D");				// burner drive letter
		m_sRootPath		= _T("c:\\baotest");	// where are the source files?

		if (InitNero())
		{
			// open the passed drive - should already be spun up by the control program
			cout << _T("Waiting for Drive ") << (LPCTSTR)m_sDriveLetter << _T(":") << endl;
			if (OpenDevice(m_sDriveLetter))
			{
				BurnDVD();
				NeroCloseDevice (m_hDevice);
			}
			else
				cerr << _T("Failed to open device ") <<  (LPCTSTR)m_sDriveLetter << _T(". Aborting Burn") << endl;
		}
		else
			cerr << _T("Failed to initialize Nero. Aborting Burn") << endl;

		CoUninitialize();
	}

	return nRetCode;
}

//---------------------------------------------------------------------------

void DeAllocate()
{
	if (m_pBurnAtOnce)
		delete m_pBurnAtOnce;
	if (m_pContainer)
		delete m_pContainer;
}

//---------------------------------------------------------------------------

bool InitNero()
{
	bool bResult = false;

	if (!NeroAPIGlueConnect(NULL)) 
	{
		cout << _T("Cannot connect to NeroAPI") << endl;
	}
	else
	{
		NEROAPI_INIT_ERROR initErr=NeroInit (&NeroSettings,NULL);
		switch (initErr) 
		{
			case NEROAPI_INIT_OK:
				bResult = true;
				break;
			case NEROAPI_INIT_INVALID_ARGS:
				NeroError ("NeroInit() : invalid args");
				break;
			case NEROAPI_INIT_INVALID_SERIAL_NUM:
				NeroError ("NeroInit() : invalid serial number");
				break;
			case NEROAPI_INIT_DEMOVERSION_EXPIRED:
				NeroError ("NeroInit() : demo version has expired");
				break;
			case NEROAPI_INIT_CANNOT_LOCK:
				NeroError ("NeroInit() : cannot lock");
				break;
			default:
			case NEROAPI_INIT_UNSPECIFIED_ERROR:
				NeroError ("NeroInit() : unspecified error");
		}
	}
	return bResult;
}

//---------------------------------------------------------------------------

bool OpenDevice(LPCTSTR pszDriveName)
{
	bool bResult = false;
	NERO_SCSI_DEVICE_INFO *pSelectedDeviceInfo;

	m_pNeroDeviceInfo = NeroGetAvailableDrivesEx (MEDIA_DVD_ANY,NULL);
	if (!m_pNeroDeviceInfo)
	{
		NeroError ("NeroGetAvailableDrives()");
	}

	for (int i = 0; i < m_pNeroDeviceInfo->nsdisNumDevInfos; i++) 
	{
		char driveLetter;
		if (m_pNeroDeviceInfo->nsdisDevInfos[i].nsdiDriveLetter)
			driveLetter = m_pNeroDeviceInfo->nsdisDevInfos[i].nsdiDriveLetter;
		else
			driveLetter = '?';

		if (!stricmp(pszDriveName, m_pNeroDeviceInfo->nsdisDevInfos[i].nsdiDeviceName)
			|| (strlen(pszDriveName)==1 && toupper(pszDriveName[0])==toupper(driveLetter)))
		{
			m_hDevice = NeroOpenDevice (&m_pNeroDeviceInfo->nsdisDevInfos[i]);
			pSelectedDeviceInfo=&m_pNeroDeviceInfo->nsdisDevInfos[i];
			if (!m_hDevice) 
			{
				NeroError ((LPSTR)pszDriveName);
			}
			break;
		}
	}
	if (!m_hDevice)
		cout << _T("Drive %s not found") << pszDriveName;
	else
		bResult = true;

	return bResult;
}

//---------------------------------------------------------------------------

void BurnDVD()
{
	int res = 0;
	char *error = NULL;
	int iResult = 0;
	CString sError;

	// the files to be burnt
	LPCTSTR aszFiles[] = {	_T("VTS_01_1.VOB"),
							_T("VTS_01_0.IFO"),
							_T("VTS_01_0.BUP"),
							_T("VIDEO_TS.IFO"),
							_T("VIDEO_TS.BUP")
							};

	const int iFileCount = (sizeof(aszFiles) / sizeof(aszFiles[0]));

	// setup file system container
	m_pContainer = NeroCreateFileSystemContainer(NULL);
	m_pBurnAtOnce = new NERO_WRITE_BURN_AT_ONCE;
	ZeroMemory((LPVOID)m_pBurnAtOnce, sizeof(NERO_WRITE_BURN_AT_ONCE));
	m_pBurnAtOnce->nwbaoSize = sizeof(NERO_WRITE_BURN_AT_ONCE);
	m_pBurnAtOnce->nwbaoTempDirectory = NULL;
	m_pBurnAtOnce->nwbaoFSContainer = m_pContainer;

	// I've tried quite a few combinations - doesn't seem to matter what I do here
	DWORD dwFlags = NBF_WRITE | NBF_CD_TEXT | NBF_BUF_UNDERRUN_PROT | NBF_DISABLE_ABORT | NBF_SPEED_IN_KBS | NBF_DVDP_BURN_30MM_AT_LEAST
					| BTS_DVD_ROM | NCITEF_CREATE_ISO_FS
					| NCITEF_CREATE_UDF_FS | NCITEF_DVDVIDEO_CMPT | NCITEF_DVDVIDEO_REALLOC;
	DWORD dwSpeed =	10820;	// speed in KB/s
	CString sPath, sFile;
	int iPriority = -1;	// make all priorities -1, doesn't seem to make any difference ...

	// set the volume name
	m_pContainer->SetName(_T("BAOTEST"));

	// Get the root directory container
	FileSystemContent::IDirectoryContainer *pRoot = m_pContainer->Root();

	// add audio dir to the container
	FileSystemContent::IDirectoryContainer * pAudioDir = pRoot->AddDirectory(_T("AUDIO_TS"), iPriority);

	// add video dir to the container
	FileSystemContent::IDirectoryContainer * pVideoDir = pRoot->AddDirectory(_T("VIDEO_TS"), iPriority);

	// add some files to the container
	for (int i = 0; i < iFileCount; i++)
	{
		sFile = aszFiles[i];

		// use static files - fails anyway
		sPath.Format(_T("%s\\dvd\\video_ts\\%s"), m_sRootPath, sFile);
	
		// I would like to use dynamically generated vobs & ifos, but I can't even get the basic thing to work
		FileSystemContent::IDirectoryEntryContainer *pDirEntry = pVideoDir->AddFile(sFile, sPath, iPriority, iPriority);

		DWORD dwError = GetLastError();
		error = NeroGetLastError ();
		if (error)
			cout << _T("Error Adding File ") << (LPCTSTR)sPath << _T(" Error :") << error << endl;
		else
			cout << _T("Added File ") << (LPCTSTR)sPath << endl;
	}

	cout << _T("Starting NeroBurnAtOnce") << endl;
	res = NeroBurnAtOnce(	m_hDevice,
							m_pBurnAtOnce,
							dwFlags,
							dwSpeed,
							&NeroProgress,
							m_pBurnAtOnce->nwbaoReserved);

	sError = NeroGetLastError();

	cout << _T("NeroBurn complete. Status = [") << (LPCTSTR)sError << _T("]") << endl;

	DeAllocate();
}

// nero callback functions follow ...

Here’s the Nero software info from Nero InfoTool 4.03:

Software Information
--------------------
Operating System     : Windows XP Professional (5.01.2600 Service Pack 2)
Country              : United States
Language             : English
ANSI Code Page       : 1252
OEM Code Page        : 437
DirectX              : DirectX 9.0c

Description          : Nero Burning ROM
Version              : 7, 2, 3, 3
Company              : Nero AG
Version Check        : Ok

Description          : Nero BurnRights Control Panel
Version              : 2, 0, 0, 6
Company              : Nero AG

Description          : Nero CD - DVD Speed
Version              : 4, 6, 1, 2
Company              : Nero AG

Description          : Nero DriveSpeed
Version              : 3, 0, 6, 0
Company              : Nero AG

Description          : Nero StartSmart
Version              : 3, 2, 2, 0
Company              : Nero AG

Description          : Nero Library
Version              : 7, 2, 3, 3
Company              : Nero AG

Description          : Nero Vision
Version              : 4,5,0,27
Company              : Nero AG

Description          : Nero Scout
Version              : 1, 2, 0, 13
Company              : Nero AG

End of message.