Tytus Kosiarski Poziom 11

Joined: 29 Jul 2007 Posts: 74
|
#33
27 Dec 2011 16:30 Re: Mały odtwarzacz MP3,AAC,MP4 na AT91SAM7S256 |
|
|
|
Witam:) Dzięki:) Dokumentacja odtwarzacza i dokładniejszy kosztorys jest w moim poście otwierającym ten wątek, całość wynosi tak ok 340zł. Nie przewiduję robienia z tego kitu w celach zarobkowych z dwóch powodów: 1. nie wiem,jak by było z prawami autorskimi, ale wydaje mi się, że kodu dekodera MP3 i AAC nie można wykorzystywać w celach komercyjnych;
2. nie mam możliwości zaprogramowania procesora poza układem. Jedynie w zmontowanym układzie odtwarzacza. Mogę doradzić jedynie poskładanie we własnym zakresie tego odtwarzacza (z wykorzystaniem dokumentacji) i dogadanie się ze mną na priv w celu zaprogramowania i uruchomienia całości.
Obecnie testuję poprawność odtwarzania plików MP4 (walka ze zwisami w wyjątkach Data Abort podczas odtwarzania tych plików). Wydaję mi się, że już odtwarzanie przebiega poprawnie, jak już będę pewien poprawności działania, wystawię, oczywiście, kod. Mogę również napomknąć, że pomału przygotowuję się do implementacji kodu tego odtwarzacza na procesorze ATSAM3S4B (pinowo zgodny z SAM7S, ale rdzeń procesora to Cortex M3). Ale to jeszcze zajmie mi czasu... (również chroniczny brak, niestety)
Pozdrawiam, KT
|
|
Tytus Kosiarski Poziom 11

Joined: 29 Jul 2007 Posts: 74
|
#35
26 Feb 2012 01:39 Re: Mały odtwarzacz MP3,AAC,MP4 na AT91SAM7S256 |
|
|
|
Witam
OK, po ponad dwumiesięcznej, intensywnej eksploatacji mp-czwórki wyszły na jaw błędy w programie, które kończyły się wyjątkiem Data Abort i "zwisem". Jedną z przyczyn udało się dość łatwo namierzyć, mianowicie wyjątek ten powodowany był tylko podczas odtwarzania jednego, specyficznego pliku MP4. Okazało się, że w tym pliku atom "stsc" składał się tylko z jednego 12-bajtowego wpisu, w którym to wpisie były: 4 bajty indeksu kawałka audio, 4 bajty ilości próbek audio w tym kawałku (ta próbka audio to jest pojedyncza, "surowa" ramka AAC, bez nagłówka ADTS) oraz 4 bajty Sample Duration Index (czas trwania pojedynczej próbki(?); zawsze równy 1). Te ostatnie 4 bajty SDI nie są mi potrzebne i nie wykorzystuję ich. W tym konkretnym pliku we wpisie atomu "stsc" indeks kawałka audio miał wartość 1, natomiast ilość próbek audio w tym kawałku danych była różna od 1 (a nie równa 1, jak w innych plikach z podobnie zbudowanym atomem "stsc"). Po "obczajeniu" tej różnicy w budowie atomu "stsc" wystarczyło wstawić po dwukropku:
max_nSamples_for_chunk = k + (number_of_chunk_entries > 1 ? n_audio_samples_in_chunk : /*zwiększenie liczby przetworzonych próbek audio o liczbę próbek w nowym kawałku audio*/ stsc_atom_table[(n_elements_of_stsc_atom_table - (n_processed_entries_of_stsc_atom - i)) + 1]); /*lub o liczbę próbek pamiętaną w drugim elemencie stsc_atom_table, gdy number_of_chunk_entries == 1*/
zamiast wartości 1 w pętli odtwarzającej plik MP4 w funkcji play_mp4_file w pliku play_files.c. Ta zmiana spowodowała poprawne już odtwarzanie tego konkretnego pliku MP4.
Z inną przyczyną wyjątku Data Abort nie było już tak prosto - zawieszanie się w przypadkowych momentach, przy odtwarzaniu różnych plików. Było czasami tak, że cały katalog z plikami MP4 był poprawnie odtworzony do końca, po czym podczas próby ponownego odtworzenia zawartości tego katalogu zwis następował już na pierwszym pliku. Próby manewrowania rozmiarami heap'u i stack'a nie dawały jakiejś widocznej zmiany, nie mówiąc o poprawie. Wielogodzinne odtwarzanie tych plików w trybie debug-u ujawniło w końcu, że problem występuje podczas wykonywania się jednej funkcji RefillBitstreamCache w pliku aac_bitstream.c oraz drugiej funkcji DecodeSectionData w pliku noiseless.c. Wiele czasu zajęło mi ustalenie, co mogło być przyczyną takich problemów. Na właściwy trop naprowadziła mnie obserwacja wartości zmiennej
bsi->cachedBits w funkcji GetBits w pliku aac_bitstream.c podczas debug-u. Normalnie wartość ta powinna być >=0, gdy jest mniejsza, to w tej funkcji wywoływana jest kolejna funkcja RefillBitstreamCache. Podczas normalnego, prawidłowego dekodowania wartość zmiennej bsi->cachedBits nie była mniejsza niż (-16). Natomiast przed momentem zwisu wartość ta była, owszem, ujemna, ale przyjmowała "kosmiczne" wielkości!!! Wtedy kapnąłem się, że przyczyną takiego zachowania mogą być błędy w odczycie danych odtwarzanego pliku z karty SD (przekłamywanie bajtów). Błędy odczytu niekiedy zdarzały się na tyle rzadko, że możliwe było odtworzenie całego, kilkugodzinnego podkatalogu z plikami MP4 bez zwisów. Zastanawiając się, co by z tym zrobić, pomyślałem, że warto by było wykorzystać sumę kontrolną CRC generowaną przez kartę SD do wyeliminowania błędów odczytu. Dwubajtowa suma kontrolna CRC jest doklejana na końcu każdego 512-bajtowego sektora danych podczas odczytywania karty SD. Wartości CRC wpisuję do tablicy wskazywanej przez wskaźnik SD_CRC_table jak w poniższym kodzie (funkcja sd_get_response_and_read_write_data w pliku SD_Card_functions.c):
case CMD17: //gdy wysłana była do karty SD komenda odczytu pojedynczego bloku danych z karty memset(SD_CRC_table, 0, 2); //wyczyszczenie tablicy przechowującej kody CRC odczytywane z karty SD ... ... AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SD_Card_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK odebrany_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI); //i teraz odczytywanie starszego bajtu CRC SD_CRC_table[0] = (odebrany_bajt) << 8; //oraz wpisanie go do elementu [0] tablicy przechowującej sumy CRC i przesunięcie go na starszy bajt tego elementu AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SD_Card_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK odebrany_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI); //i teraz odczytywanie młodszego bajtu CRC SD_CRC_table[0] = SD_CRC_table[0] | odebrany_bajt; //i wpisanie go na młodszy bajt elementu [0] tablicy przechowującej sumy CRC break; case CMD18: //gdy wysłana była do karty SD komenda odczytu kilku bloków danych z karty, to poniżej memset(SD_CRC_table, 0, (liczba_blokow * 2)); //wyczyszczenie tablicy przechowującej kody CRC odczytywane z karty SD while (liczba_blokow) { attempt = 0; ... ... AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SD_Card_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK odebrany_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI); //i teraz odczytywanie starszego bajtu CRC SD_CRC_table[liczba_blokow - 1] = (odebrany_bajt) << 8; /*oraz wpisanie go do elementu [liczba_blokow - 1] tablicy przechowującej sumy CRC i przesunięcie go na starszy bajt tego elementu*/ AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SD_Card_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK odebrany_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI); //i teraz odczytywanie młodszego bajtu CRC SD_CRC_table[liczba_blokow - 1] = (SD_CRC_table[liczba_blokow - 1]) | odebrany_bajt; /*i wpisanie go na młodszy bajt elementu [liczba_blokow - 1] tablicy przechowującej sumy CRC*/ liczba_blokow--; //i zmniejszenie o 1 liczby bloków do odczytu, bo jeden sektor karty został już odczytany } ... ...
Następnie zapamiętane kody CRC wykorzystuję do porównania z obliczonymi kodami CRC i stosownie do wyniku porównania, ponownego odczytania uprzednio błędnie odczytanych danych, jak w poniższym kodzie (funkcje read_sector i read_multiple_sectors w pliku SD_Card_functions.c):
char read_sector(...) { ... ... do /*ta pętla do...while wykonuje się tak długo, jak długo kod CRC odczytany z SD razem z 512-bajtowym sektorem <> obliczonego CRC z danych 512-bajtowego sektora przechowywanego w tablicy adres_tablicy*/ { //i poprawny odczyt z karty (read_OK == true) komenda = send_command(CMD17,(adres * mnoznik)); /*wysłanie do karty komendy READ_SINGLE_BLOCK - odczytanie pojedynczego bloku danych poczynając od bajtu o adresie w zmiennej adres*/ read_OK = sd_get_response_and_read_write_data(adres_tablicy, komenda, 1, CRC16); /*w odpowiedzi karta zwraca odpowiedź R1, oraz, gdy nie ma błędu, 512 bajtów sektora o podanym adresie w zmiennej adres + 2 bajty CRC przechowywane w tablicy CRC16*/ calculated_CRC16 = 0; for (i = 0; i < 512; i++) /*w tej pętli obliczenie CRC na podstawie danych w adres_tablicy, odczytanych wcześniej z SD*/ { calculated_CRC16 = (calculated_CRC16 << 8) ^ CCITT_table[((calculated_CRC16 >> 8) ^ adres_tablicy[i])]; } } while ( (CRC16[0] != calculated_CRC16) && read_OK); ... ... } char read_multiple_sectors(...) { ... ... komenda = send_command(CMD18,(adres * mnoznik)); /*wysłanie do karty komendy READ_MULTIPLE_BLOCK - odczytanie kilku bloków danych poczynając od bajtu o adresie w zmiennej adres*/ read_OK = sd_get_response_and_read_write_data(adres_tablicy, komenda, liczba_sektorow, CRC16); /*w odpowiedzi karta zwraca odpowiedź R1, oraz, gdy nie ma błędu, (512 * liczba_sektorow) bajtów poczynając od sektora o podanym adresie w zmiennej adres*/ for (k = 0; k < liczba_sektorow; k++) /*w tej pętli obliczanie kodu CRC każdego 512-bajtowego kawałka z tablicy adres_tablicy i następnie porównywanie go z każdym kodem CRC odczytanym z SD i pamiętanym w tablicy CRC16*/ { calculated_CRC16 = 0; for (i = (k * 512); i < ((k * 512) + 512); i++) /*w tej pętli obliczenie CRC na podstawie każdego 512-bajtowego kawałka danych w adres_tablicy, odczytanych wcześniej z SD*/ { calculated_CRC16 = (calculated_CRC16 << 8) ^ CCITT_table[((calculated_CRC16 >> 8) ^ adres_tablicy[i])]; } if (calculated_CRC16 != CRC16[(liczba_sektorow - 1) - k]) //i gdy obliczony CRC <> odczytanego CRC z karty, to read_OK = read_sector((adres_tablicy + (k * 512)), (adres + k), rodzaj_karty); /*ponowny odczyt tylko tego sektora z karty SD, w którym wystąpiły błędy, pozostałe, będące OK, nie są ruszane*/ } ... ... }
Na razie działa:) Wykorzystałem sposób obliczania CRC CCITT z tej strony: http://groups.google.com/group/pl.comp.lang.delphi/browse_thread/thread/ef7c8fcf5605b9eb?fwc=1
oraz tablicę wielomianu CCITT stąd: http://www.elektroda.pl/rtvforum/topic1350530.html
Ponadto zmniejszyłem wykorzystanie RAMU do 48kB poprzez usunięcie trzech wielkich tablic ze zmiennych globalnych i dynamiczne tworzenie tych tablic jedynie przed rozpoczęciem odtwarzania pliku MP3, AAC i MP4 oraz usuwaniem tych tablic po zakończeniu odtwarzania tych plików, gdyż przymierzam się powoli do implementacji tego odtwarzacza na procesorze SAM3S4B.
Pozdrawiam, KT
| Filename: |
odtwarzacz_MP3_AAC_MP4.zip |
 Download |
| Contents: |
|
| Filesize: |
756.33 KB |
| Punkty: |
0 |
|
|