This program plays QuickTime movies on GR-Peach
Dependencies: AsciiFont GR-PEACH_video GraphicsFramework LCD_shield_config R_BSP TLV320_RBSP mbed-rtos mbed
Requirements
- GR-Peach
- GR-Peach Audio Camera Shield or I²S compatible audio DAC
- GR-Peach LCD Shield
- USB memory stick
How to play movie files
- Encode movie files
encode movies with ffmpeg
$ ffmpeg -i <input -ar 44100 -acodec pcm_s16le -s 480x270 -vcodec mjpeg -q:v 3 -movflags faststart -threads 4 -vf fps=30 <output>.mov
- Copy movies to the root directory of USB memory
- Build and upload this program
- Run it
Diff: main.cpp
- Revision:
- 0:d0f130e27d32
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Mar 10 11:30:02 2017 +0000 @@ -0,0 +1,290 @@ +#include "mbed.h" +#include "USBHostMSD.h" +#include "usb_host_setting.h" +#include "LCD.hpp" +#include "MovFile.hpp" +#include "TLV320_RBSP.h" +#include "MovPlayer.hpp" +#include "AsciiFont.h" +#include "BinaryImage_RZ_A1H.h" +#include "CppStandardHelper.hpp" + +#define USE_TLV320 + +static constexpr int FRAME_BUFFER_BYTE_PER_PIXEL = 2; +static constexpr int FRAME_BUFFER_STRIDE = ((LCD_PIXEL_WIDTH * FRAME_BUFFER_BYTE_PER_PIXEL) + 31u) & ~31u; +static uint8_t MBED_ALIGN(32) user_frame_buffer[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]; + +static constexpr int FileNameBufferNum = 16; +static constexpr int FileNameBufferLength = 32; +static char filenameBuffer[FileNameBufferNum][FileNameBufferLength]; + +static rtos::Semaphore touchSemaphore(0); + +#ifdef ONLINE_COMPILER +namespace TouchAction { +#endif +ENUM TouchAction { + None, + Play0, + Play1, + Play2, + ScrollUp, + ScrollDown +}; +#ifdef ONLINE_COMPILER +} +#endif + +namespace Menu { + const graphics_image_t *top = menu; + const graphics_image_t *one = menu1; + const graphics_image_t *two = menu2; + const graphics_image_t *three = menu3; + const graphics_image_t *down = menud; + const graphics_image_t *up = menuu; + const graphics_image_t *upx = menuux; + const graphics_image_t *downx = menudx; +} + +static void dcache_clean(void * p_buf, uint32_t size) { + uint32_t start_addr = (uint32_t)p_buf & 0xFFFFFFE0; + uint32_t end_addr = (uint32_t)p_buf + size; + uint32_t addr; + + /* Data cache clean */ + for (addr = start_addr; addr < end_addr; addr += 0x20) { + __v7_clean_dcache_mva((void *)addr); + } +} + +static void touchCallback() +{ + touchSemaphore.release(); +} + +#ifdef ONLINE_COMPILER +static TouchAction::TouchAction readTouch(LCD *lcd, TouckKey_LCD_shield *touch, const graphics_image_t *currentImage) +#else +static TouchAction readTouch(LCD *lcd, TouckKey_LCD_shield *touch, const graphics_image_t *currentImage) +#endif +{ + TouchKey::touch_pos_t touchPos; + printf("waiting for touch\n"); + touchSemaphore.wait(); + printf("touch detected\n"); + touch->GetCoordinates(1, &touchPos); +#ifdef ONLINE_COMPILER + TouchAction::TouchAction ret = TouchAction::None; +#else + TouchAction ret = TouchAction::None; +#endif + const graphics_image_t *image = nullptr; + int touchNum = 1; + if (40 <= touchPos.x && touchPos.x <= 360) { + if (35 <= touchPos.y && touchPos.y <= 70) { + ret = TouchAction::Play0; + image = Menu::one; + } else if (115 <= touchPos.y && touchPos.y <= 155) { + ret = TouchAction::Play1; + image = Menu::two; + } else if (195 <= touchPos.y && touchPos.y <= 235) { + ret = TouchAction::Play2; + image = Menu::three; + } + } else if (409 <= touchPos.x && touchPos.x <= 460) { + if (22 <= touchPos.y && touchPos.y <= 68) { + ret = TouchAction::ScrollUp; + image = Menu::up; + } else if (202 <= touchPos.y && touchPos.y <= 248) { + ret = TouchAction::ScrollDown; + image = Menu::down; + } + } + if (lcd && image) { + lcd->drawImage(image); + } + while (touchNum) { + touchSemaphore.wait(); + touchNum = touch->GetCoordinates(1, &touchPos); + } + if (lcd) { + lcd->drawImage(currentImage); + } + return ret; +} + +int main(int MBED_UNUSED argc, const char MBED_UNUSED * argv[]) +{ + DigitalOut usb1en(P3_8); + USBHostMSD msd("usb"); + usb1en = 1; + rtos::Thread::wait(5); + usb1en = 0; + + DigitalOut led(LED1); + while (! msd.connect()) { + printf("not connected\n"); + rtos::Thread::wait(500); + led = ! led; + } + led = 0; + + LCD *lcd = LCD::singleton(); + lcd->start(); + +#ifdef USE_TLV320 + TLV320_RBSP audio(P10_13, I2C_SDA, I2C_SCL, P4_4, P4_5, P4_7, P4_6, + 0x80, MovPlayer::BufferLength - 1, 0); + audio.power(0x02); + audio.format(16); + audio.frequency(44100); + MovPlayer::AudioCallback callback(&audio, &TLV320_RBSP::write); +#else + R_BSP_Ssif audio(P2_4, P2_5, P2_7, P2_6, 0x80, MovPlayer::BufferLength - 1, 0); + ssif_channel_cfg_t ssif_cfg; + ssif_cfg.enabled = true; + ssif_cfg.int_level = 0x78; + ssif_cfg.slave_mode = false; + ssif_cfg.sample_freq = 44100u; + ssif_cfg.clk_select = SSIF_CFG_CKS_AUDIO_X1; + ssif_cfg.multi_ch = SSIF_CFG_MULTI_CH_1; + ssif_cfg.data_word = SSIF_CFG_DATA_WORD_16; + ssif_cfg.system_word = SSIF_CFG_SYSTEM_WORD_16; + ssif_cfg.bclk_pol = SSIF_CFG_FALLING; + ssif_cfg.ws_pol = SSIF_CFG_WS_HIGH; + ssif_cfg.padding_pol = SSIF_CFG_PADDING_LOW; + ssif_cfg.serial_alignment = SSIF_CFG_DATA_FIRST; + ssif_cfg.parallel_alignment = SSIF_CFG_LEFT; + ssif_cfg.ws_delay = SSIF_CFG_NO_DELAY; + ssif_cfg.noise_cancel = SSIF_CFG_ENABLE_NOISE_CANCEL; + ssif_cfg.tdm_mode = SSIF_CFG_DISABLE_TDM; + ssif_cfg.romdec_direct.mode = SSIF_CFG_DISABLE_ROMDEC_DIRECT; + ssif_cfg.romdec_direct.p_cbfunc = NULL; + audio.ConfigChannel(&ssif_cfg); + MovPlayer::AudioCallback callback(&audio, &R_BSP_Ssif::write); +#endif + + DisplayBase Display; + memset(user_frame_buffer, 0, sizeof(user_frame_buffer)); + dcache_clean(user_frame_buffer, sizeof(user_frame_buffer)); + DisplayBase::rect_t rect; + rect.vs = 0; + rect.vw = LCD_PIXEL_HEIGHT; + rect.hs = 0; + rect.hw = LCD_PIXEL_WIDTH; + Display.Graphics_Read_Setting(DisplayBase::GRAPHICS_LAYER_1, (void *)user_frame_buffer, + FRAME_BUFFER_STRIDE, DisplayBase::GRAPHICS_FORMAT_ARGB4444, + DisplayBase::WR_RD_WRSWA_32_16BIT, &rect); + Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_1); + + AsciiFont ascii(user_frame_buffer, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT, + FRAME_BUFFER_STRIDE, FRAME_BUFFER_BYTE_PER_PIXEL); + + TouckKey_LCD_shield touch(P4_0, P2_13, I2C_SDA, I2C_SCL); + touch.SetCallback(touchCallback); + touch.Reset(); + + MovFile *mov = MovFile::sharedFile(); + MovPlayer *player = MovPlayer::defaultPlayer(); + + memset(filenameBuffer, 0, FileNameBufferNum * FileNameBufferLength); + DIR *directory = opendir("/usb/"); + struct dirent *file = NULL; + int numOfMovies = 0; + while (numOfMovies < FileNameBufferNum && (file = readdir(directory))) { + size_t length = strlen(file->d_name); + if (file->d_name[0] == '.') { + continue; + } + if (memcmp(&file->d_name[length - 4], ".mov", 4)) { + continue; + } + strcpy(filenameBuffer[numOfMovies], "/usb/"); + strcat(filenameBuffer[numOfMovies], file->d_name); + ++numOfMovies; + } + closedir(directory); + + int fileIndex = 0; + const graphics_image_t *currentImage = Menu::upx; + lcd->drawImage(Menu::upx); + constexpr uint32_t black = 0x000000f0; + + while (1) { + ascii.DrawStr(&filenameBuffer[fileIndex][5], 0, 30, black, 2); + ascii.DrawStr(&filenameBuffer[fileIndex + 1][5], 0, 110, black, 2); + ascii.DrawStr(&filenameBuffer[fileIndex + 2][5], 0, 190, black, 2); + dcache_clean(user_frame_buffer, sizeof(user_frame_buffer)); +#ifdef ONLINE_COMPILER + TouchAction::TouchAction action = readTouch(lcd, &touch, currentImage); +#else + TouchAction action = readTouch(lcd, &touch, currentImage); +#endif + char *path = nullptr; + switch (action) { + case TouchAction::Play0: + path = filenameBuffer[fileIndex]; + break; + + case TouchAction::Play1: + path = filenameBuffer[fileIndex + 1]; + break; + + case TouchAction::Play2: + path = filenameBuffer[fileIndex + 2]; + break; + + case TouchAction::ScrollUp: + fileIndex -= 3; + if (fileIndex <= 0) { + fileIndex = 0; + currentImage = Menu::upx; + } else { + currentImage = Menu::top; + } + lcd->drawImage(currentImage); + ascii.Erase(); + dcache_clean(user_frame_buffer, sizeof(user_frame_buffer)); + break; + + case TouchAction::ScrollDown: + fileIndex += 3; + if (fileIndex + 3 >= numOfMovies) { + fileIndex = numOfMovies - 3; + if (fileIndex < 0) { + fileIndex = 0; + } + currentImage = Menu::downx; + } else { + currentImage = Menu::top; + } + lcd->drawImage(currentImage); + ascii.Erase(); + dcache_clean(user_frame_buffer, sizeof(user_frame_buffer)); + break; + + default: + break; + } + if (path && *path) { + ascii.Erase(); + dcache_clean(user_frame_buffer, sizeof(user_frame_buffer)); + FILE *file = fopen(path, "r"); + printf("start playing %s\n", path); + mov->start(file); + player->play(mov, lcd, callback); + fclose(file); + printf("finished playing\n"); + } else { + continue; + } + touch.Reset(); + while (touchSemaphore.wait(0) > 0) ; + readTouch(nullptr, &touch, nullptr); + lcd->drawImage(currentImage); + } + + return 0; +} +