Не удается создать файл AVI с видео и аудио (VFW) в приложении Delphi 6
Я пытаюсь написать приложение Delphi 6, которое берет видео и аудио и записывает их в AVI с использованием сервисов VFW. Мне удалось заставить видео работать правильно. Хорошо играет в VLC или Windows Media Player. Но когда я затем добавляю аудиопоток и пытаюсь воспроизвести выходной AVI, проигрыватель VLC жалуется на разрыв файла AVI. Будет воспроизведен файл и видео выглядит нормально, но нет звука. Я попытался добавить аудиопоток перед записью видеопотока, а затем после него. Ни один не работал.
Кроме того, если я не добавляю аудиопоток, я могу щелкнуть правой кнопкой мыши выходной файл AVI в проводнике Windows и на вкладке "Сводка" я могу увидеть необходимую информацию для видеоданных в потоке. После добавления потока вместо щелчка правой кнопкой мыши отображается сообщение о состоянии, в котором говорится, что свойства AVI не могут быть прочитаны.
ОБНОВЛЕНИЕ: я делаю что-то действительно в принципе неправильно. Оказывается, что-то, что я делаю, уносит заголовок верхнего уровня файла. Если я не создаю аудиопоток, файл в порядке, и я вижу обычную информацию заголовка в самом начале файла. В тот момент, когда я звоню, чтобы создать аудиопоток, второй поток, который я создаю, заголовок в самом начале выходного файла AVI полностью пуст (нули). Даже если я не вызываю AVIStreamSetFormat() и не записываю какие-либо данные (и даже если я это делаю), просто выполнение этого второго вызова AVICreateStream() стирает самое начало файла при проверке файла с помощью шестнадцатеричного редактора. Что я мог сделать, это вызывает эту сумму, если "повреждение" выходного файла.
Мой вопрос:
1) Что я делаю не так? 2) Знаете ли вы хороший пример, который показывает, как создать AVI с чередованием аудио и видео, особенно тот, который также показывает, как записать сжатый аудиопоток?
Вот код, который я использую для записи аудиопотока, после того как я полностью записал видеопоток. У переменной уровня FAvi уже заполнено поле TWaveFormatEx (wfx). Я проверил содержимое, и все поля настроены на допустимые значения частоты дискретизации 8000 кГц, 1 канала, 16 бит на канал и тега формата 1 (WAVE_FORMAT_PCM). Выравнивание блоков, скорость передачи данных и т. Д. Тоже правильно заполнены:
function TAviWriterWithCompression.addAudioFrame(dat: Pointer; numbytes: Cardinal): HRESULT;
var
bRetErr: boolean;
numsamps: LongInt;
ahdr: TAVISTREAMINFO;
hr: HRESULT;
lSampWritten, lBytesWritten: LONG;
begin
Result := S_OK;
bRetErr := true;
if Assigned(FAvi_) then
begin
if Assigned(dat) and (numbytes <> 0) then
begin
if not FAvi_.iserr then
begin
if FAvi_.wfx.nChannels <> 0 then
bRetErr := false
else
Result := LongInt(AVIERR_BADFORMAT);
end
else
Result := LongInt(AVIERR_ERROR);
end
else
Result := LongInt(AVIERR_BADPARAM);
end
else
Result := LongInt(AVIERR_BADHANDLE);
if bRetErr then
// =========================== EXIT POINT ==============
exit;
if FAvi_.wfx.wBitsPerSample <= 0 then
begin
Result := LongInt(AVIERR_BADFORMAT);
// =========================== EXIT POINT ==============
exit;
end; // if FAvi_.wfx.wBitsPerSample <= 0 then
numsamps := Trunc((numbytes * 8) / FAvi_.wfx.wBitsPerSample);
if ((numsamps * FAvi_.wfx.wBitsPerSample / 8) <> numbytes) then
begin
Result := LongInt(AVIERR_BADPARAM);
// =========================== EXIT POINT ==============
exit;
end; // if ((numsamps * FAvi_.wfx.wBitsPerSample/8) <> numbytes) then
if not Assigned(FAvi_.theAs) then
begin
ZeroMemory(@ahdr, sizeof(ahdr));
ahdr.fccType := streamtypeAUDIO;
ahdr.dwScale := FAvi_.wfx.nBlockAlign;
ahdr.dwRate := FAvi_.wfx.nSamplesPerSec*FAvi_.wfx.nBlockAlign;
ahdr.dwSampleSize := FAvi_.wfx.nBlockAlign;
ahdr.dwQuality := DWORD(-1);
hr := AVIFileCreateStream(FAvi_.pfile, FAvi_.theAs, ahdr);
if hr <> AVIERR_OK then
begin
Result := hr;
// Set the error flag.
FAvi_.iserr := true;
// =========================== EXIT POINT ==============
exit;
end; // if hr <> AVIERR_OK then
hr := AVIStreamSetFormat(FAvi_.theAs, 0, @FAvi_.wfx, sizeof(FAvi_.wfx));
if hr <> AVIERR_OK then
begin
Result := hr;
// Set the error flag.
FAvi_.iserr := true;
// =========================== EXIT POINT ==============
exit;
end; // if hr <> AVIERR_OK then
end; // if not Assigned(FAvi_.theAs) then
// now we can write the data
hr := AVIStreamWrite(FAvi_.theAs, FAvi_.nsamp, numsamps, dat, numbytes, AVIIF_KEYFRAME, @lSampWritten, @lBytesWritten);
if hr <> AVIERR_OK then
begin
Result := hr;
// Set the error flag in our utility object.
FAvi_.iserr := true;
// =========================== EXIT POINT ==============
exit;
end; // if hr <> AVIERR_OK then
Inc(FAvi_.nsamp, numsamps);
// Set the flag that tells it is no longer a virgin file and that
// attempting to set the compression is not allowed.
FIsVirginFile := false;
end;
Вот код, который очищает аудио и видео поток при завершении:
destructor TAviWriterWithCompression.Destroy;
begin
// Code goes here.
if Assigned(FAvi_) then
begin
// Release the streams.
if Assigned(FAvi_.theAs) then
begin
AVIStreamRelease(FAvi_.theAs);
FAvi_.theAs := nil;
end;
if Assigned(FAvi_.thePsCompressed) then
begin
AVIStreamRelease(FAvi_.thePsCompressed);
// FAvi_.thePsCompressed := nil;
end;
if Assigned(FAvi_.thePs) then
begin
AVIStreamRelease(FAvi_.thePs);
// FAvi_.thePs := nil;
end;
if Assigned(FAvi_.pfile) then
begin
AVIFileRelease(FAvi_.pfile);
// FAvi_.pfile := nil;
end;
AVIFileExit();
// FreeAndNil(FAvi_);
end; // if Assigned(FAvi_) then
inherited Destroy;
end;
Уведомить: @RemyLebau
1 ответ
На следующей странице есть компонент под названием "TAVIWriter":
http://www.efg2.com/Lab/Library/Delphi/Graphics/FileFormatsAndConversion.htm
который включает полный исходный код компонента и демонстрацию того, как его можно использовать.