Не удается создать файл 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

который включает полный исходный код компонента и демонстрацию того, как его можно использовать.

Другие вопросы по тегам