Просмотрев несклько черно-белых JPEG файлов пожатых с хорошим качеством выяснил, что заголовок (до маркера FFDA)
находится в пределах 0,8 - 1,5%. Округлил до 2%.
Закодировал заголовок циклическим кодом (7, 4).
CODE
#include <stdio.h>
#include <stdlib.h>
#define BSIZE 512
short int coder(unsigned char);
int main(int argc, char *argv[])
{
unsigned char bufRead[BSIZE], buf2uc[2], a;
FILE *fdWrite, *fdRead;
short int numByte = 0, buf2si[2], i, ac;
int cnt = 0;
fdRead = fopen("a.dat", "rb");
if (fdRead == NULL)
{
printf ("Oshibka pri otkritii faila Read\n");
exit(1);
}
else
printf ("\nFile Read otkrit\n");
fdWrite = fopen("acode.dat","wb");
if (fdWrite == NULL)
{
printf ("Oshibka pri otkritii faila Write\n");
exit(1);
}
else
printf ("File Write otkrit\n");
do
{
fread(bufRead, sizeof(unsigned char), BSIZE, fdRead);
for (i = 0; i < (BSIZE - 1); i++)
{
if ((bufRead[i] == 0xff) && (bufRead[i+1] == 0xda))
{
numByte = cnt*(BSIZE-1) + i + 2;
break;
}
}
if (numByte == 0)
{
cnt++;
fseek(fdRead, -1, SEEK_CUR);
}
}
while (numByte == 0);
printf("\nKodirovat bait %i\n", numByte);
memcpy(buf2uc, &numByte, sizeof buf2uc);
buf2si[0] = coder(buf2uc[0]);
buf2si[1] = coder(buf2uc[1]);
fwrite(buf2si, sizeof(short int), 2, fdWrite);
fseek(fdRead, 0, SEEK_SET);
for (i = 0; i < numByte; i++)
{
fread(&a, sizeof(unsigned char), 1, fdRead);
ac = coder(a);
fwrite(&ac, sizeof(short int), 1, fdWrite);
}
fread(&a, sizeof(unsigned char), 1, fdRead);
while (!feof(fdRead))
{
fwrite(&a, sizeof(unsigned char), 1, fdWrite);
fread(&a, sizeof(unsigned char), 1, fdRead);
}
if (fclose (fdRead) == 0)
printf ("File Read zakrit\n");
else
printf ("Oshibka pri zakritii faila Read\n");
if (fclose (fdWrite) == 0)
printf ("File Write zakrit\n");
else
printf ("Oshibka pri zakritii faila Write\n");
getch();
return 0;
}
short int coder(unsigned char a)
{
unsigned char aH, aH_Code, aL, aL_Code;
short int i, Code;
/*
a - байт введённый для кодирования.
aH - полученный остаток от деления старших 4 бит.
aH_Code - значение закодированных 4 старших бит.
aL - полученный остаток от деления младших 4 бит.
aL_Code - значение закодированных 4 младших бит.
Code - 2 байтное число, в младшем байте содержится 7 битное число
полученное при кодировании младших 4 бит введеного числа.
В старшем байте - значение закодированных старших 4 бит.
*/
// складываем с маской для обнуления ненужных бит
// в aH хранится старший полубайт его сдвигаем вправо на два разряда
// чтобы коменсировать первый сдвиг влево в цикле
aH = a & 0xf0;
aH_Code = aH >> 1;
aH = aH >> 2;
// складываем с маской для обнуления ненужных бит
// в aL хранится младший полубайт его сдвигаем влево на два разряда
// (надо на три), третий сдвиг - первый сдвиг влево в цикле
aL = a & 0x0f;
aL_Code = aL << 3;
aL = a << 2;
// aH_Code и aL_Code хранят исходные полубайты
// сдвинутые на три разряда влево относительно первого
// к ним происходит присоединение остатка
for (i = 0; i < 4; i++)
{
aH = aH << 1;
if (aH & 0x40)
aH = aH ^ 0x58;
aL = aL << 1;
if (aL & 0x40)
aL = aL ^ 0x58;
}
// остаток получается сдвинутым на 3 разряда влево,
// поэтому надо сдвинуть его вправо
aH = aH >> 3;
aH_Code = aH_Code | aH;
aL = aL >> 3;
aL_Code = aL_Code | aL;
//16 битному числу Code присваеваем в старший байт aH_Code,
//а в младший байт aL_Code
Code = aH_Code;
Code = Code << 8;
Code = Code | aL_Code;
return Code;
}
После моделировал ошибку с помощью следующей программы:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i, P_err, indention;
unsigned char masErr[8] = {1,2,4,8,16,32,64,128}, a, err;
FILE *fdRead;
long fileSize, pos;
unsigned char fileName[100];
printf ("Vvedite imya faila: ");
scanf("%s", fileName);
printf ("Na skolko byte otstupit ot nachala faila: ");
scanf("%i", &indention);
printf ("Vvedite chislo byte na kotorie prixoditsa 1 oshibka: ");
scanf("%i", &P_err);
fdRead = fopen(fileName, "r+b");
if (fdRead == NULL)
{
printf ("Oshibka pri otkritii faila Read\n");
exit(1);
}
else
printf ("\nFile Read otkrit\n");
fseek(fdRead,0,SEEK_END);
fileSize = ftell(fdRead);
printf("\nThe size of file is %ld bytes\n", fileSize);
srand(time(NULL));
for (i = (indention + P_err - 1); i < fileSize; i = i + P_err)
{
fseek(fdRead, i - rand()%P_err, SEEK_SET);
// pos = ftell(fdRead);
// printf("Pos SEEK_SET+i %i \n", pos);
fread(&a, sizeof(unsigned char), 1, fdRead);
// pos = ftell(fdRead);
// printf("Pos SEEK_SET+i %i posle chteniya simvola %x\n", pos, a);
err = masErr[rand()%8];
a = a ^ err;
// printf("simvol %x posle ^ c %x\n", a, err);
fseek(fdRead, -1, SEEK_CUR);
// pos = ftell(fdRead);
// printf("Pos SEEK_SET+i-1 %i \n---------------------\n", pos);
fwrite(&a, sizeof(unsigned char), 1, fdRead);
}
if (fclose (fdRead) == 0)
printf ("File Read zakrit\n");
else
printf ("Oshibka pri zakritii faila Read\n");
getch();
return 0;
}
Ну и декодер исправляющий ошибки в закодированной части файла.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BSIZE 512
unsigned char decoder(short int);
int main(int argc, char *argv[])
{
unsigned char bufRead[BSIZE], buf2uc[2], a;
FILE *fdWrite, *fdRead;
long position;
short int numByte, buf2si[2], i, ac;
int cnt = 0, razn = 0;
fdRead = fopen("acode.dat", "rb");
if (fdRead == NULL)
{
printf ("Oshibka pri otkritii faila Read\n");
exit(1);
}
else
printf ("\nFile Read otkrit\n");
fdWrite = fopen("adecode.dat","wb");
if (fdWrite == NULL)
{
printf ("Oshibka pri otkritii faila Write\n");
exit(1);
}
else
printf ("File Write otkrit\n");
fread(buf2si, sizeof(short int), 2, fdRead);
buf2uc[0] = decoder(buf2si[0]);
buf2uc[1] = decoder(buf2si[1]);
memcpy(&numByte, buf2uc, sizeof buf2uc);
for (i = 0; i < numByte; i++)
{
fread(&ac, sizeof(short int), 1, fdRead);
a = decoder(ac);
fwrite(&a, sizeof(unsigned char), 1, fdWrite);
}
fread(&a, sizeof(unsigned char), 1, fdRead);
while (!feof(fdRead))
{
fwrite(&a, sizeof(unsigned char), 1, fdWrite);
fread(&a, sizeof(unsigned char), 1, fdRead);
}
if (fclose (fdRead) == 0)
printf ("File Read zakrit\n");
else
printf ("Oshibka pri zakritii faila Read\n");
if (fclose (fdWrite) == 0)
printf ("File Write zakrit\n");
else
printf ("Oshibka pri zakritii faila Write\n");
getch();
return 0;
}
unsigned char decoder(short int c)
{
unsigned char cL, cH, cH_Decode, cL_Decode, Decode;
short int i;
/*
с - 2 байтное число введённый для декодирования.
сH - полученный остаток от деления старшего байта.
сH_Decode - значение декодированных 4 старших бит.
сL - полученный остаток от деления младшего байта.
cL_Decode - значение декодированных 4 младших бит.
Deode - 1 байтное декодированное число.
*/
cL_Decode = (unsigned char)c;
c = c >> 8;
cH_Decode = (unsigned char)c;
cH = cH_Decode;
cL = cL_Decode;
for (i = 0; i < 4; i++)
{
if (cH & 0x40)
cH = cH ^ 0x58;
cH = cH << 1;
if (cL & 0x40)
cL = cL ^ 0x58;
cL = cL << 1;
}
cH = cH >> 4;
cL = cL >> 4;
switch(cH)
{
case 1:
printf ("oshibka v 1 bite\n");
cH_Decode = cH_Decode ^ 1;
break;
case 2:
printf ("oshibka v 2 bite\n");
cH_Decode = cH_Decode ^ 2;
break;
case 4:
printf ("oshibka v 3 bite\n");
cH_Decode = cH_Decode ^ 4;
break;
case 3:
printf ("oshibka v 4 bite\n");
cH_Decode = cH_Decode ^ 8;
break;
case 6:
printf ("oshibka v 5 bite\n");
cH_Decode = cH_Decode ^ 16;
break;
case 7:
printf ("oshibka v 6 bite\n");
cH_Decode = cH_Decode ^ 32;
break;
case 5:
printf ("oshibka v 7 bite\n");
cH_Decode = cH_Decode ^ 64;
break;
default:
break;
}
cH_Decode = cH_Decode & 0x78;
Decode = cH_Decode << 1;
cH_Decode = cH_Decode >> 3;
switch(cL)
{
case 1:
printf ("oshibka v 1 bite\n");
cL_Decode = cL_Decode ^ 1;
break;
case 2:
printf ("oshibka v 2 bite\n");
cL_Decode = cL_Decode ^ 2;
break;
case 4:
printf ("oshibka v 3 bite\n");
cL_Decode = cL_Decode ^ 4;
break;
case 3:
printf ("oshibka v 4 bite\n");
cL_Decode = cL_Decode ^ 8;
break;
case 6:
printf ("oshibka v 5 bite\n");
cL_Decode = cL_Decode ^ 16;
break;
case 7:
printf ("oshibka v 6 bite\n");
cL_Decode = cL_Decode ^ 32;
break;
case 5:
printf ("oshibka v 7 bite\n");
cL_Decode = cL_Decode ^ 64;
break;
default:
break;
}
cL_Decode = cL_Decode >> 3;
cL_Decode = cL_Decode & 0x0f;
Decode = Decode | cL_Decode;
return Decode;
}
Код конечно не оптимален, написан для проверки идеи.
Как результат:
При внесении нескольких ошибок в незакодированный файл, он зачастую не открывался. Видимо когда
ошибки приходились на заголовок.
При кодировании, внесении ошибок и декодировании, файл стабильно открывается, но даже несколько ошибок в данных
зачастую делают его визуально безнадёжно испорченным.
Очевидно данные тоже надо кодировать, причем как можно лучше.
Так как 2% избыточности из допустимых 10% использованно, то максимально допустимый вариант БЧХ (127, 120).