2016-04-29 3 views
1

Я написал программу Delphi, которая создает файлы MJPEG, длина которых может составлять несколько ГБ. JPG снимаются с камеры DirectX с использованием DSPack. Эта часть отлично работает и создает файл JPG-изображений в формате:Delphi 7: Чтение блока байтов из TFileStream и копирование в TMemorySTream

FF D8 .... (данные изображения) ... FF D9 FF D8 .... (данные изображения) ... FF D9 FF D8 и т. Д.

FF D8 обозначает начало JPG и FF D9 обозначает конец. Каждый JPG составляет около 21 КБ.

Теперь я пытаюсь написать подходящий плеер MJPEG.

В процедуре FormCreate форме, я создать FileStream и отобразить первый JPG, который работает отлично:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    b: Array[0..1] of Byte; 
    jpg: TJPEGImage; 
begin 
: 
: 
    MemoryStream:= TMemoryStream.Create; 
    jpg:= TJPEGImage.Create; 

    MJPEGStream:= TFileStream.Create(MJPEGFileName, fmOpenRead); 

    MJPEGStream.Position:= 0; 

    repeat         
     MJPEGStream.Read(b[0], 2);   // Find end of first jpg 
     MemoryStream.Write(b[0], 2);   // and write to memory 
    until (b[0] = $FF) and (b[1] = $D9); 

    MemoryStream.Position:= 0; 
    jpg.LoadFromStream(memoryStream); 
    Image1.Picture.Assign(jpg); 
    MemoryStream.Free; 
    jpg.Free; 
end; 

Я оставляю FileStream так, надеюсь, его указатель положения удерживается открытым. У меня есть кнопка в форме, цель которой состоять в том, чтобы перетащить один JPG за один раз, но, хотя первый «jog» продвигает один JPG, последующие пробежки продвигаются случайным числом раз. Вот процедура:

procedure TForm1.btnJogForwardClick(Sender: TObject); 
var 
    b: Array[0..1] of Byte; 
    jpg: TJPEGImage; 

begin 
    MemoryStream:= TMemoryStream.Create; 
    try 
     repeat 
      MJPEGStream.Read(b[0], 2); 
      MemoryStream.Write(b[0], 2); 
     until ((b[0] = $FF) and (b[1] = $D9)); 

     MemoryStream.Position:= 0; 
     jpg:= TJPEGImage.Create; 
     try 
     try 
      jpg.LoadFromStream(MemoryStream); 
      Image1.Picture.Assign(jpg); 
     except 
     end; 
     finally 
     jpg.Free; 
     end; 
    finally 
     MemoryStream.Free; 
    end; 

Я проверил с игроком третьей партии MJPEG и что может подталкивать кадр за кадром, так что я знаю, что файл MJPEG нормально. Любые предложения относительно того, почему моя процедура не является равномерным по очереди, будут оценены по достоинству.

Thanks, John.

+0

Чтение и запись двух байтов одновременно будет очень неэффективным. Вам нужна буферизация. –

+0

Это немного вяло, но я не уверен, как читать/писать больший блок, не теряя позиции двух конечных байтов (и оставлять указатель готовым в следующем байте Start). Хотя это медленно, я думаю, что если я не смогу заставить это работать, я бы действительно боролся с чем-то более сложным! – vwlowen

+3

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

ответ

1

Спасибо за комментарии и предложения. Кажется, мне удалось разобраться.

const 
    JPGSizeMax = 100000; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    b: Array[0..JPGSizeMax] of Byte; 
: 
: 
begin 
: 
: 
MJPEGStream:= TFileStream.Create(MJPEGFileName, fmOpenRead); 
MJPEGStream.Position:= 0; 

MJPEGStream.Read(b[0], JPGSizeMax); 
for i:= 0 to JPGSizeMax do 
begin 
    if (b[i] = $D9) and (b[i-1] = $FF) then 
    begin 
    Count:= i; 
    break; 
    end; 
end; 

MemoryStream.Write(b[0], Count); 
FilePosition:= Count + 1; 

MemoryStream.Position:= 0; 
jpg.LoadFromStream(memoryStream); 
Image1.Picture.Assign(jpg); 

MemoryStream.Free; 
jpg.Free; 

конец;

Процедура для кнопки Jog является так же:

MJPEGStream.Position:= FilePosition; 

MJPEGStream.Read(b[0], JPGSizeMax); 
for i:= 0 to JPGSizeMax do 
begin 
    if (b[i] = $D9) and (b[i-1] = $FF) then 
    begin 
    Count:= i; 
    break; 
    end; 
end; 

    memoryStream.Write(b[0], Count); 
    FilePosition:= FilePosition + count + 1; 

// etc 

Еще раз спасибо за указание мне в правильном направлении.

John.

Смежные вопросы