MJPEG to JPEG C++/Delphi
Some years go i received task to receive/record/play from DCS IP camera, it support MPEG4 and MJPEG stream via RTSP/RTP, so problem was:
1. Implement RTSP (just part that will enough to receive stream)
2. Parse/Record received stream
To implement RTSP was enough 1 day of RFC and Sockets dump learning, to recording stream i wrote simple mpeg4/mjpeg parser that split stream to frames and than we can use methods from avifil32.dll
But when i done my employer said: “If we chose to receive mjpeg stream i wanna have possibility to save frame to jpeg file”. That was a problem. i spent much time for research
but task was done
So what we need for that?
a) Write to file JPEG header
b) Write DHT color segment
c) Remove Avi header from MJPEG frame and write result
d) thats all
#include "mjpegtojpeg.hpp"
bool mjpeg2Jpeg(const char *fileName, const byte *buffer, const int size)
{
HANDLE file_ = CreateFile(fileName,
GENERIC_WRITE | GENERIC_READ,
0, NULL,
CREATE_ALWAYS,
0, NULL);
if (file_ == INVALID_HANDLE_VALUE)
{
return false;
}
byte jpgHdr[] =
{
0xff, 0xd8, // SOI
0xff, 0xe0, // APP0
0x00, 0x10, // APP0 Hdr size
0x4a, 0x46, 0x49, 0x46, 0x00, // ID string
0x01, 0x01, // Version
0x00, // Bits per type
0x00, 0x00, // X density
0x00, 0x00, // Y density
0x00, // X Thumbnail size
0x00 // Y Thumbnail size
};
unsigned long wrote = 0;
//write header
if (!WriteFile(file_, jpgHdr, sizeof (jpgHdr), &wrote, NULL))
{
CloseHandle(file_);
return false;
}
byte MJPGDHTSeg[0x1A4] =
{
/* JPEG DHT Segment for YCrCb omitted from MJPG data */
0xFF, 0xC4, 0x01, 0xA2,
0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24,
0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62,
0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
0xF9, 0xFA
};
//Write DHT color segment
if (!WriteFile (file_, MJPGDHTSeg, sizeof (MJPGDHTSeg), &wrote, NULL))
{
CloseHandle(file_);
return false;
}
//removing avi header
int tmp = *(buffer + 4);
tmp <<= 8;
tmp += *(buffer + 5) + 4;
//write frame
if (!WriteFile (file_, buffer + tmp, size - tmp, &wrote, NULL))
{
CloseHandle(file_);
return false;
}
CloseHandle(file_);
return true;
}
unit mjpegtojpeg;
interface
uses windows;
const
MJPGDHTSeg : array[1..$1A4] of byte =
(
{ JPEG DHT Segment for YCrCb omitted from MJPG data }
$FF, $C4, $01, $A2,
$00, $00, $01, $05, $01, $01, $01, $01, $01, $01, $00, $00, $00, $00, $00, $00, $00, $00,
$01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $01, $00, $03, $01, $01, $01, $01,
$01, $01, $01, $01, $01, $00, $00, $00, $00, $00, $00, $01, $02, $03, $04, $05, $06, $07,
$08, $09, $0A, $0B, $10, $00, $02, $01, $03, $03, $02, $04, $03, $05, $05, $04, $04, $00,
$00, $01, $7D, $01, $02, $03, $00, $04, $11, $05, $12, $21, $31, $41, $06, $13, $51, $61,
$07, $22, $71, $14, $32, $81, $91, $A1, $08, $23, $42, $B1, $C1, $15, $52, $D1, $F0, $24,
$33, $62, $72, $82, $09, $0A, $16, $17, $18, $19, $1A, $25, $26, $27, $28, $29, $2A, $34,
$35, $36, $37, $38, $39, $3A, $43, $44, $45, $46, $47, $48, $49, $4A, $53, $54, $55, $56,
$57, $58, $59, $5A, $63, $64, $65, $66, $67, $68, $69, $6A, $73, $74, $75, $76, $77, $78,
$79, $7A, $83, $84, $85, $86, $87, $88, $89, $8A, $92, $93, $94, $95, $96, $97, $98, $99,
$9A, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $B2, $B3, $B4, $B5, $B6, $B7, $B8, $B9,
$BA, $C2, $C3, $C4, $C5, $C6, $C7, $C8, $C9, $CA, $D2, $D3, $D4, $D5, $D6, $D7, $D8, $D9,
$DA, $E1, $E2, $E3, $E4, $E5, $E6, $E7, $E8, $E9, $EA, $F1, $F2, $F3, $F4, $F5, $F6, $F7,
$F8, $F9, $FA, $11, $00, $02, $01, $02, $04, $04, $03, $04, $07, $05, $04, $04, $00, $01,
$02, $77, $00, $01, $02, $03, $11, $04, $05, $21, $31, $06, $12, $41, $51, $07, $61, $71,
$13, $22, $32, $81, $08, $14, $42, $91, $A1, $B1, $C1, $09, $23, $33, $52, $F0, $15, $62,
$72, $D1, $0A, $16, $24, $34, $E1, $25, $F1, $17, $18, $19, $1A, $26, $27, $28, $29, $2A,
$35, $36, $37, $38, $39, $3A, $43, $44, $45, $46, $47, $48, $49, $4A, $53, $54, $55, $56,
$57, $58, $59, $5A, $63, $64, $65, $66, $67, $68, $69, $6A, $73, $74, $75, $76, $77, $78,
$79, $7A, $82, $83, $84, $85, $86, $87, $88, $89, $8A, $92, $93, $94, $95, $96, $97, $98,
$99, $9A, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $B2, $B3, $B4, $B5, $B6, $B7, $B8,
$B9, $BA, $C2, $C3, $C4, $C5, $C6, $C7, $C8, $C9, $CA, $D2, $D3, $D4, $D5, $D6, $D7, $D8,
$D9, $DA, $E2, $E3, $E4, $E5, $E6, $E7, $E8, $E9, $EA, $F2, $F3, $F4, $F5, $F6, $F7, $F8,
$F9, $FA
);
jpgHdr : array[1..20] of byte =
(
$ff, $d8, // SOI
$ff, $e0, // APP0
$00, $10, // APP0 Hdr size
$4a, $46, $49, $46, $00, // ID string
$01, $01, // Version
$00, // Bits per type
$00, $00, // X density
$00, $00, // Y density
$00, // X Thumbnail size
$00 // Y Thumbnail size
);
function mjpeg2Jpeg(const fileName: string; const buffer : Pointer; const size : integer) : boolean;
implementation
function mjpeg2Jpeg(const fileName: string; const buffer : Pointer; const size : integer) : boolean;
var
wrote : longword;
tmp : integer;
file_ : THandle;
begin
Result := False;
file_ := CreateFile(PChar(fileName),
GENERIC_WRITE or GENERIC_READ,
0, nil,
CREATE_ALWAYS,
0, 0);
if (file_ = INVALID_HANDLE_VALUE) then
begin
exit;
end;
//write header
if (not WriteFile(file_, jpgHdr[1], 20, wrote, nil)) then
begin
CloseHandle(file_);
exit;
end;
if (not WriteFile (file_, MJPGDHTSeg[1], $1A4, wrote, nil)) then
begin
CloseHandle(file_);
exit;
end;
//removing avi header
tmp := Integer(Pointer(Integer(buffer) + 4));
tmp := tmp shl 8;
tmp := tmp + Integer(Pointer(Integer(buffer) + 5)) + 4;
//write frame
if (not WriteFile (file_, Pointer(Integer(buffer) + tmp)^, size - tmp, wrote, nil)) then
begin
CloseHandle(file_);
exit;
end;
CloseHandle(file_);
Result := True;
end;
end.
you can download sources here
Filed under: Programming
March 14th, 2010 at 6:21 pm
Thank you very much! You are really helped me!
March 18th, 2010 at 7:46 pm
Year, thanks for helping
September 15th, 2010 at 9:25 am
can you post the same code in c# ?
March 12th, 2011 at 7:51 pm
Can someone tell, how this same thing can be done in linux system?