Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Biblioteka DCT, iDCT i JPEG dla ARM7TDMI.

atom1477 05 Oct 2009 12:29 9198 77
Computer Controls
  • #61
    atom1477
    Level 43  
    Dobra.
    Zrobiłem nowego Make Targeta i poszło. Jest libjpeg.a.
    Ale też zajmuje ze 300kB.
    Przekopiowuje do głównego katalogu, kompiluje i mam:

    Biblioteka DCT, iDCT i JPEG dla ARM7TDMI.

    Może to są te dziwne błędy a o których mówiłeś, ale skoro przekompilowałem to za pomocą gcc to powinno ich nie być, tak?
    Brakuje jakichś funkcji. Ale chyba nie w syscalls. Bo jak usunę coś z syscalls to błąd jest inny
  • Computer Controls
  • Helpful post
    #62
    Freddie Chopin
    MCUs specialist
    To są te dziwne błędy, ale skoro je widzisz, to chyba to przekompilowanie Ci nie wyszło. Biblioteka skompilowana w gcc, a nie g++, zajmuje około 30kB mniej (coś koło 270kB jeśli dobrze pamiętam).

    Przed rekompilacją biblioteki proponuję zrobić "cs-make clean", bo bez tego wcale jej nie rekompilujesz.

    4\/3!!
  • Computer Controls
  • #63
    atom1477
    Level 43  
    Niestety, Clean nic nie daje. Zresztą usuwam libjpeg.a przed nową kompilacją a to chyba powinno wymusić nową kompilację.
    Może Clean robię źle. Robię takie ogólne Clean. Nie wiem jak zrobić tylko w katalogu libjpeg.

    EDIT1.
    Dobra. Wpisałem cs-make clean i nie chciało pójść.
    Ale jak zmieniłem na cs-make to przekompilowało. 269kB.

    Program główny też się kompiluje.
    Wielkie dzięki za pomoc.

    Zostaje tylko spróbować coś skompresować ;p


    EDIT2.
    Zmodyfikowałem trochę kod wywalając obsługę plików:
    Code:

    int compress_jpeg(unsigned char *image_buffer, int w, int h, unsigned char **mem_dest);


    volatile uint8_t tablica_RGB[64*64*3];
    volatile uint8_t tablica_jpeg[32768];
    volatile uint32_t rozmiar_jpeg;

    //volatile uint8_t *wskaznik_RGB;
    //volatile uint8_t *wskaznik_jpeg;
    //-------------------------------------------------------------------------
    int main (void)
    {
       volatile uint32_t count, count_max=1000000;

       system_init();
       pll_start();


            FIO4DIR |= (1 << 31);                         // P4.31  LED pin - output
            FIO3DIR |= (1 << 22);                         // P3.22  LED pin - output

            FIO4SET = (1 << 31);      //Red
            for(count=0; count<count_max; count++);
            FIO4CLR = (1 << 31);      //Red
            for(count=0; count<count_max; count++);
            FIO4SET = (1 << 31);      //Red
            for(count=0; count<count_max; count++);
            FIO4CLR = (1 << 31);      //Red
            for(count=0; count<count_max; count++);

            //wskaznik_RGB = tablica_RGB;     //Użycie & powodowało warninga
            //wskaznik_jpeg = tablica_jpeg;     //Użycie & powodowało warninga

             compress_jpeg(tablica_RGB, 64, 64, tablica_jpeg);


            FIO3SET = (1 << 22);

            while (1)
                {

                }


    }
    //-------------------------------------------------------------------------
    typedef struct {
       struct jpeg_destination_mgr pub; /* public fields */
       JOCTET * buffer;      /* start of buffer */
       unsigned char n;
       unsigned int jpeg_size;
    } moj_destination_mgr;

    typedef moj_destination_mgr * moj_dest_ptr;


    GLOBAL(void)
    jpeg_mem_dest (j_compress_ptr cinfo);


    int compress_jpeg(unsigned char *image_buffer, int w, int h, unsigned char **mem_dest)
    {
      struct jpeg_compress_struct cinfo;
      struct jpeg_error_mgr jerr;
      uint i;

       cinfo.err = jpeg_std_error(&jerr);
       jpeg_create_compress(&cinfo);

       jpeg_mem_dest(&cinfo);                   // store jpeg image in memory

       cinfo.image_width = w;                   // image width and height, in pixels
       cinfo.image_height = h;

       i = 3;                                    //3 Colors RGB
       cinfo.input_components = i;               // # of color components per pixel
       cinfo.in_color_space = JCS_RGB;           // colorspace of input image
       jpeg_set_defaults(&cinfo);
       jpeg_set_quality (&cinfo, 80, TRUE);
       cinfo.dct_method = JDCT_IFAST;               // colorspace of input image
       FIO4SET = (1 << 31);                         //Red    <-----------------------------------To się wykonuje
       jpeg_start_compress(&cinfo, TRUE);
       FIO3SET = (1 << 22);                         //Green  <-----------------------------------To już nie
       JSAMPROW row_pointer[1];               // pointer to a single row
       int row_stride = cinfo.image_width * i;            // physical row width in buffer
       FIO3CLR = (1 << 22);
       while (cinfo.next_scanline < cinfo.image_height)
           {
           row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
           jpeg_write_scanlines(&cinfo, row_pointer, 1);
           }
       FIO3CLR = (1 << 22);
       jpeg_finish_compress(&cinfo);
       moj_dest_ptr dest = (moj_dest_ptr) cinfo.dest;
       jpeg_destroy_compress(&cinfo);

        *mem_dest = dest->buffer;

        rozmiar_jpeg = dest->jpeg_size;

        return dest->jpeg_size;
    }

    METHODDEF(void)
    init_destination (j_compress_ptr cinfo) {
       moj_dest_ptr dest = (moj_dest_ptr) cinfo->dest;
       dest->buffer = (JOCTET *)malloc(OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
       dest->pub.next_output_byte = dest->buffer;
       dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
       dest->n = 1; dest->jpeg_size = 0;
    }

    METHODDEF(boolean)
    empty_output_buffer (j_compress_ptr cinfo) {
       moj_dest_ptr dest = (moj_dest_ptr) cinfo->dest;
       dest->n++;
       dest->buffer = (JOCTET *)realloc(dest->buffer, dest->n * OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
       dest->pub.next_output_byte = dest->buffer + (dest->n-1) * OUTPUT_BUF_SIZE;
       dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
       return TRUE;
    }

    METHODDEF(void)
    term_destination (j_compress_ptr cinfo) {
       moj_dest_ptr dest = (moj_dest_ptr) cinfo->dest;
       size_t datacount = dest->n * OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
       dest->jpeg_size = datacount;
    }

    GLOBAL(void)
    jpeg_mem_dest (j_compress_ptr cinfo) {
      moj_dest_ptr dest;
      if (cinfo->dest == NULL) {   /* first time for this JPEG object? */
        cinfo->dest = (struct jpeg_destination_mgr *)
          (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                  SIZEOF(moj_destination_mgr));
      }
      dest = (moj_dest_ptr) cinfo->dest;
      dest->pub.init_destination = init_destination;
      dest->pub.empty_output_buffer = empty_output_buffer;
      dest->pub.term_destination = term_destination;
    }
    //-------------------------------------------------------------------------


    Kompiluje się. Programuje się.
    Czerwona diodka na początku miga dwa razy więc program się uruchamia.
    Potem czerwona diodka się zaświeca na stałe.
    Zielona nie.
    Czyli mam przywiechę na funkcji:
    jpeg_start_compress(&cinfo, TRUE);

    No i nie wiem co z tym zrobić.
    Mam nieodpowiednie przekazanie parametrów do funkcji compress_jpeg, ale kompilator wywala tylko warninga więc chyba dokonuje odpowiedniej konwersji (samemu robi wskaźnik).
    Próbowałem też przekazywać bezpośrednio wskaźnik, albo zamienić typ tablicy tablica_RGB na unsigned char, ale warning zawsze jest taki sam.
    A to drugie, unsigned char **mem_dest, to jest wskaźnik na wskaźnik jak rozumiem?
    Biblioteka DCT, iDCT i JPEG dla ARM7TDMI.

    Pewnie trzeba jeszcze pogrzebać w pliku config.h.
    Tantalos: zmieniałeś tam coś? A w ogóle korzystasz z tego standardowego pliku czy z jakiegoś innego?
  • Helpful post
    #64
    Freddie Chopin
    MCUs specialist
    atom1477 wrote:
    Czyli mam przywiechę na funkcji:
    jpeg_start_compress(&cinfo, TRUE);

    No i nie wiem co z tym zrobić.

    Właśnie do tego przydają się JTAGi [;

    Quote:
    Mam nieodpowiednie przekazanie parametrów do funkcji compress_jpeg, ale kompilator wywala tylko warninga więc chyba dokonuje odpowiedniej konwersji (samemu robi wskaźnik).
    Próbowałem też przekazywać bezpośrednio wskaźnik, albo zamienić typ tablicy tablica_RGB na unsigned char, ale warning zawsze jest taki sam.
    A to drugie, unsigned char **mem_dest, to jest wskaźnik na wskaźnik jak rozumiem?

    Daleki byłbym od takich założeń, że kompilator załatwi jakieś błędy za Ciebie. ** to wskaźnik na wskaźnik (adres wskaźnika), ale w szczególnym przypadku może być to tablica dwuwymiarowa. Myślę że zamiast gdybać trzeba by poszukać dokumentacji do tego kodu i zobaczyć jak używać tych funkcji.

    4\/3!!
  • #65
    atom1477
    Level 43  
    Ale to nie są błędy tylko warningi. Czyli jednak coś z tym robi.

    Co do dokumentacji to niezbyt ona pomocna bo dotyczy tylko przypakdu zapisu do pliku.
    A ja chcę na zwykłych tablicach.
    Ten "menager" Tantalosa do tablic jest dla mnie niesamowicie niezrozumiały, ale przeglądając konstrukcję jpeg_compress_struct powoli zaczyna się wyjaśniać. Posiedzę nad tym parę dni to może dojdę co do czego.
  • Helpful post
    #66
    Freddie Chopin
    MCUs specialist
    atom1477 wrote:
    Ale to nie są błędy tylko warningi. Czyli jednak coś z tym robi.

    Uwierz, że z tym akurat nic nie robi. **ptr a *ptr to dwa zupełnie różne typy, ale obydwa zajmują (w tym przypadku) 32-bity, więc kompilator robi to co mu każesz, nawet jeśli jest to błędne.

    4\/3!!
  • Helpful post
    #69
    Tantalos
    Level 18  
    Typ **ptr to wskaźnik do wskaźnika. Jest użyty ponieważ compress_jpeg zwraca w nim adres pamięci pod którym został zapisany obraz jpeg. Dlatego powinien być użyty w taki sposób:

    Code:
    compress_jpeg(tablica_RGB, 64, 64, &tablica_jpeg);


    Druga sprawa to użyty tu output manager sam alokuje potrzebną pamięć, dlatego podajesz tylko sam wskaźnik, nie trzeba przydzielać mu żadnej wartości. Powinieneś go zadeklarować tak:

    Code:
    uint8_t *tablica_jpeg;


    OUTPUT_BUF_SIZE określa krok z jakim pamięć jest alokowana, tzn. jeśli OUTPUT_BUF_SIZE = 32768 to jeśli się okaże, że 32k to za mało to manager alokuje 64k, jeśli to też za mało to 96k itd.

    Jeśli zawiesza się na jcopmress_start to być może masz problem z funkcją malloc. Ile masz dostępnej pamięci?
  • #70
    atom1477
    Level 43  
    Ja się na C nie znam, więc poproszę kolejne wyjaśnienie ;p
    Ja bym raczej powiedział, że to zwykły wskaźnik zwraca adres pod którym jest coś zapisane.
    **ptr zwraca wskaźnik do wskaźnika. I dopiero ten drugi wskaźnik by na coś wskazywał.

    Teraz kod który podałeś:
    Rozumiem że do tablicy:
    Quote:
    compress_jpeg(tablica_RGB, 64, 64, &tablica_jpeg);

    Zostanie utworzony wskaźnik i to on będzie przekazany.
    A do tego:
    Quote:
    compress_jpeg(tablica_RGB, 64, 64, &tablica_jpeg);

    Zostanie utworzony wskaźnik. Potem drugi wskaźnik do pierwszego wskaźnika i do funkcji zostanie przekazany ten drugi wskaźnik. Tak?

    Co do dostępnej pamięci. Na razie mam ze 30kB. Tablice już mam, ale ten Twój menager alokuje dodatkową pamięć i w niej zwraca wynik. Czyli mogę usunąć moją tablicę wyjściową.
    Acha. Jak mam 64KB RAMu i 8MB SDRAMu (pamięci oczywiście są nieciągłe), to malloc przejdzie z RAMu do SDRAMu samemu? Czy nie działa to na nieciągłej pamięci?

    Zawieszanie się jcopmress_start wynika pewnie z próby dostępu do nieistniejącego adresu. W końcu wcześniej przekazywałem „wskaźnik” do jakichś śmieci.

    A po co mi wskaźnik:
    uint8_t *tablica_jpeg;
    ?
    Przecież nigdzie się go nie przekazuje?
    Po za tym pod nazwą tablica_jpeg mam już tablicę wyjściową.

    Coś mnie się zdaje że się pomyliłeś i chodziło Ci o takie coś:
    Quote:
    compress_jpeg(wskaznik_RGB, 64, 64, &wskaznik_jpeg);

    Wtedy wszystko by się zgadzało z moim tokiem myślenia.

    Niestety, Twój czy mój kod - warningi zupełnie takie same a program nadal ma przywiechę.
  • Helpful post
    #71
    Tantalos
    Level 18  
    Miałem na myśli, żebyś zamienił deklarację volatile uint8_t tablica_jpeg[32768]; na uint8_t *tablica_jpeg; , manager jpeg sam alokuje pamięć i nie trzeba jej przydzielać jak zrobiłeś w volatile uint8_t tablica_jpeg[32768]; . Taka deklaracja od razu zabiera 32k , a pozostałe 30k to trochę mało, dużych obrazków nie obrobi. Manager na samym początku alokuje 32k jeśli OUTPUT_BUF_SIZE masz 32768. Może zmniejsz do np. 8192, bo jeśli przydzieliłeś 32k zmiennej tablica_jpeg i manager zabiera pozostałe 32k to będzie zwiecha, brak pamięci. Malloc nie przejdzie z RAM do SDRAM niestety.
  • Helpful post
    #72
    wojtekkk09
    Level 15  
    Tantalos wrote:
    Malloc nie przejdzie z RAM do SDRAM niestety.


    myślę, że to tylko kwestia dobrze napisanego _sbrk.

    Pozdrawiam
    wojt
  • #73
    atom1477
    Level 43  
    Quote:

    Miałem na myśli, żebyś zamienił deklarację volatile uint8_t tablica_jpeg[32768]; na uint8_t *tablica_jpeg;

    W zasadzie nie muszę tego zmieniać.
    Wskaźnik już ma. Po prostu muszę go wykorzystać. I wywalić tą tablicę.
    Wcześnie wskaźnik nakierowywałem na tą tablicę. Zupełnie zapomniałem że ta funkcja i tak zmienia ten wskaźnik.
    Najdziwniejsze dla mnie jest to, że niezależnie od tego co przekazuje, to funkcji warniki są takie same.

    OUTPUT_BUF_SIZE mam ustawione na 4096, więc to nie jest problem. A kompresuję obrazek 64x64 pixele.
    Jak tylko zadziała to pierwszą rzeczą będzie pozbycie się malloc-a i użycie wskaźnika do klasycznej tablicy, którą umieszczę sobie w SDRAMie.
    Tantalos: sam pisałeś ten maganer wyjścia?

    Quote:

    Malloc nie przejdzie z RAM do SDRAM niestety.

    No to mam kolejny argument żeby nie wykorzystywać dynamicznej alokacji pamięci ;p
    Ostatecznie na początek mógł bym się zgodzić na alokowanie pamięci w całości w SDRAMie, ale jak się domyślam tego zrobić prosto też się nie da.
    A edytować _sbrk raczej nie zamierzam.

    Dodatkowo - jak chcę użyć Twojego pliku libjpeg.a to wywala mi błędy że nie może znaleźć funkcji z biblioteki - jpeg_start_compress i podobnych.
    „Działa” tylko na moim libjpeg.a.
    Może Twój jest lepszy, bo przetestowany. A mój skompilowany aby było, bez zastanawiania się nad zawartością plików konfiguracyjnych.
    Ale niestety Twojego libjpeg.a użyć nie mogę, bo po prostu nie działa.


    Edit: Ok. Mam za mało RAMu. Okazało się że tylko 3700B.
    Profilaktycznie zwiększyłem rozmiary stosów do 4096B i zapomniałem sprawdzić ponownie zużycie RAMu.

    Edit2. Nie mogłem się powstrzymać i przetestowałem. No i nie wierzę ;p
    Chyba działa. W ciągu może 50ms coś robi. Trochę krótki ten czas, ale obrazek jest mały więc chyba kompresuje. Niestety nie mam jak sprawdzić czasu działania na większych obrazkach, bo pamięci brakuje.
    Obsługi SDRAMu jeszcze nie wrzuciłem do tego projektu. Ale i to nie miało by sensu.
    Muszę dorobić interfejs przesyłający obrazki BMP do ARMa i odbierający z niego pliki JPEG.
    Jak się okaże że działa to zmienię menager wyjścia i będę w domu.
    Dzięki wszystkim za pomoc.
  • Helpful post
    #74
    Freddie Chopin
    MCUs specialist
    atom1477 wrote:
    Profilaktycznie zwiększyłem rozmiary stosów do 4096B i zapomniałem sprawdzić ponownie zużycie RAMu.

    Jeśli nie używasz przerwań (a pewnie na razie nie używasz), to na prawdę rozmiar innych stosów niż user_system może być równy zero. Jeśli zaś używasz, to 4kB na stos przerwań również jest przesadą - przecież to zwykle jedna, krótka funkcja. Może w porywach 256B jest wtedy potrzebne. I to też nie do wszystkich przerwań jakie są (ABORT, SWI itp.) tylko do tych trybów których używasz.

    Co co _sbrk() / malloc(), które automatycznie przechodziłyby z jednego obszaru w drugi, to w sumie nie jest to specjalnym problemem... Nie wiem skąd nienawiść do dynamicznej alokacji - to bardzo dobra rzecz, zwłaszcza jak ma się dużo pamięci.

    4\/3!!
  • Helpful post
    #75
    Tantalos
    Level 18  
    Pisałem, że to szybki kompresor :). 50ms na obrazek 64x64 to całkiem realistyczny czas. Moja biblioteka została skompilowana przez g++ i chyba jest potrzebny myk z CPP_PREFIX, żeby działało z plikami kompilowanymi przez gcc.
    Quote:
    Tantalos: sam pisałeś ten maganer wyjścia?

    Tak i właśnie zauważyłem buga w nim.
  • #76
    atom1477
    Level 43  
    Co do Stosów. Mówiłem że profilaktycznie ;p
    Ostatecznie zamierzam zostawić 4096B na stos programu głównego na potrzeby printf-a.
    Do ABORT czy SWI to i po 32B wystarczy (kiedyś zamierzam dorobić obsługę).
    Tylko że teraz nie miałem pojęcia co jest i wszędzie pozwiększałem ;p
    CO do dynamicznej alokacji. Dobra jest jak program robi różne nieprzewidziane rzeczy. Coś trzeba zrobić to alokuje pamięć. Potem zwalnia.
    Ale mi się taki program jeszcze nie zdarzył. Zwykle robi jakąś jedna konkretną rzecz w kółko.
    Co C przekonywałem się 4 lata. Przez ten czas równolegle do dynamicznej alokacji. DO C się przekonałem. Do dynamicznej alokacji nie. Kiedyś na pewno się tym zajmę, ale obstawiam że nie wcześniej niż za rok ;p

    Tantalos: no to pewnie pomożesz mi napisać manager wyjścia do stałej tablicy ;p
    A jaki to bug? Jakiś mały chyba, bo przecież u Ciebie raczej działało, tak?


    EDIT:
    No to jestem w domu ;p
    Kompresuje.
    Wysłałem dane do kompa po RS232 i plik się otwiera się. No i oczywiście zawiera konkretną zawartość.
    Martwi mnie tylko słaba jakoś obrazu. Szczególnie że jakość ustawiłem na 80%. Może to ma nieliniową charakterystykę ustawiania jakości. Sprawdzę później dla jakości 90%.
    To samo skompresowane za pomocą IfranView zajmuje 70% tego a ma WIELOKROTNIE większą jakość.
    Na szczęście dla mnie ważniejsze jest dekompresowanie niż kompresowanie, a przy dekompresji strata jakości już nie występuje.
    Nie licząc transformaty DCT opartej na liczbach całkowitych, ale z doświadczenia wiem że różnica jest mikroskopijna w porónaniu do DCT na floatach (ale kto wie jak mocno oni to tutaj zintegerowali ;p).
    Szkoda tylko że to nie łyka formatu RGB565. Ale konwersję RGB888 a RGB565 mogę sobie jeszcze dorobić sam.
    Tak więc wielkie dzięki. I zabieram się za przerabianie managera wyjścia.
  • Helpful post
    #77
    Tantalos
    Level 18  
    Sorki ale właśnie przeczytałem dokładnie opis działania funkcji realloc i działa tak jak wcześniej myślałem, więc żadnego buga nie ma, manager wyjścia jest ok.
    Po co przeznaczasz aż 4096B dla printfa?
    W napisaniu nowego managera oczywiście mogę pomóc.
  • #78
    atom1477
    Level 43  
    Bo jak już będę miał wszystko tak jak chcę, czyli na stałych tablicach w SDRAMie to prawie cały RAM bedę miał wolny.
    Więc duży rozmiar stosu mi nie przeszkadza.
    Zresztą, to tylko deklaracja. Stos rozrośnie się i tak tak bardzo jak tylko będzie chciał. Tutaj to jeszcze kwestia kolejności ułożenia bass, stack i data i innych rzeczy, ale mniej więcej tak jest.
    Aż 4096B bo nie wiadomo jak bardzo mi printf nabroi. Czytałem że ludzie nawet 2KB przeznaczają. Czy więc te moje 4KB to aż tak wielka przesada?

    Dzięki za chęci pomocy.
    Na razie jednak posiedzę nad tym problemem o którym pisałem Ci na PW ;p