找回密码
 注册
搜索
楼主: blindholmes

[原创] 重大进展 RetroArch 专用 AI 服务接口已经写出来了

[复制链接]
 楼主| 发表于 2025-1-19 00:11 | 显示全部楼层


这个服务是 RA 请求我的接口,我返回数据给它
数据定义在 `tasks\task_translation.c` 这个文件里,从 200 行开始

  1.    /* Parse JSON body for the image and sound data */
  2.    for (;;)
  3.    {
  4.       static const char *keys[] = { "image", "sound", "text", "error", "auto", "press" };
  5.       const char *str           = NULL;
  6.       size_t str_len            = 0;
  7.       enum rjson_type json_type = rjson_next(json);

  8.       if (json_type == RJSON_DONE || json_type == RJSON_ERROR)
  9.          break;
  10.       if (json_type != RJSON_STRING)
  11.          continue;
  12.       if (rjson_get_context_type(json) != RJSON_OBJECT)
  13.          continue;
  14.       str                       = rjson_get_string(json, &str_len);

  15.       if ((rjson_get_context_count(json) & 1) == 1)
  16.       {
  17.          int i;
  18.          json_current_key = -1;

  19.          for (i = 0; i < (int)ARRAY_SIZE(keys); i++)
  20.          {
  21.             if (string_is_equal(str, keys[i]))
  22.             {
  23.                json_current_key = i;
  24.                break;
  25.             }
  26.          }
  27.       }
  28.       else
  29.       {
  30.          switch (json_current_key)
  31.          {
  32.             case 0: /* image */
  33.                raw_image_file_data = (char*)unbase64(str,
  34.                     (int)str_len, &new_image_size);
  35.                break;
  36. #ifdef HAVE_AUDIOMIXER
  37.             case 1: /* sound */
  38.                raw_sound_data = (void*)unbase64(str,
  39.                     (int)str_len, &new_sound_size);
  40.                break;
  41. #endif
  42.             case 2: /* text */
  43.                txt_str = strdup(str);
  44.                break;
  45.             case 3: /* error */
  46.                err_str = strdup(str);
  47.                break;
  48.             case 4: /* auto */
  49.                auto_str = strdup(str);
  50.                break;
  51.             case 5: /* press */
  52.                key_str = strdup(str);
  53.                break;
  54.          }
  55.          json_current_key = -1;
  56.       }
  57.    }

  58.    if (string_is_equal(err_str, "No text found."))
  59.    {
  60. #ifdef DEBUG
  61.       RARCH_LOG("No text found...\n");
  62. #endif
  63.       if (txt_str)
  64.       {
  65.          free(txt_str);
  66.          txt_str = NULL;
  67.       }

  68.       txt_str = (char*)malloc(15);
  69.       strlcpy(txt_str, err_str, 15);
  70. #ifdef HAVE_GFX_WIDGETS
  71.       if (gfx_widgets_paused)
  72.       {
  73.          /* In this case we have to unpause and then repause for a frame */
  74.          p_dispwidget->ai_service_overlay_state = 2;
  75.          command_event(CMD_EVENT_UNPAUSE, NULL);
  76.       }
  77. #endif
  78.    }

  79.    if (     !raw_image_file_data
  80.          && !raw_sound_data
  81.          && !txt_str
  82.          && !key_str
  83.          && (access_st->ai_service_auto != 2))
  84.    {
  85.       error = "Invalid JSON body.";
  86.       goto finish;
  87.    }

  88.    if (raw_image_file_data)
  89.    {
  90.       unsigned image_width, image_height;
  91.       /* Get the video frame dimensions reference */
  92.       const void *dummy_data = video_st->frame_cache_data;
  93.       unsigned width         = video_st->frame_cache_width;
  94.       unsigned height        = video_st->frame_cache_height;

  95.       /* try two different modes for text display *
  96.        * In the first mode, we use display widget overlays, but they require
  97.        * the video poke interface to be able to load image buffers.
  98.        *
  99.        * The other method is to draw to the video buffer directly, which needs
  100.        * a software core to be running. */
  101. #ifdef HAVE_GFX_WIDGETS
  102.       if (   video_st->poke
  103.           && video_st->poke->load_texture
  104.           && video_st->poke->unload_texture)
  105.       {
  106.          enum image_type_enum image_type;
  107.          /* Write to overlay */
  108.          if (     raw_image_file_data[0]    == 'B'
  109.                && raw_image_file_data[1]    == 'M')
  110.              image_type = IMAGE_TYPE_BMP;
  111.          else if (   raw_image_file_data[1] == 'P'
  112.                   && raw_image_file_data[2] == 'N'
  113.                   && raw_image_file_data[3] == 'G')
  114.             image_type = IMAGE_TYPE_PNG;
  115.          else
  116.          {
  117.             /* TODO/FIXME - localize */
  118.             RARCH_LOG("Invalid image type returned from server.\n");
  119.             goto finish;
  120.          }

  121.          if (!gfx_widgets_ai_service_overlay_load(
  122.                raw_image_file_data, (unsigned)new_image_size,
  123.                image_type))
  124.          {
  125.             /* TODO/FIXME - localize */
  126.             const char *_msg = "Video driver not supported.";
  127.             RARCH_LOG("Video driver not supported for AI Service.");
  128.             runloop_msg_queue_push(_msg, strlen(_msg), 1, 180, true, NULL,
  129.                   MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  130.          }
  131.          else if (gfx_widgets_paused)
  132.          {
  133.             /* In this case we have to unpause and then repause for a frame */
  134.             /* Unpausing state */
  135.             p_dispwidget->ai_service_overlay_state = 2;
  136.             command_event(CMD_EVENT_UNPAUSE, NULL);
  137.          }
  138.       }
  139.       else
  140. #endif
  141.       /* Can't use display widget overlays, so try writing to video buffer */
  142.       {
  143.          size_t pitch;
  144.          /* Write to video buffer directly (software cores only) */

  145.          /* This is a BMP file coming back. */
  146.          if (     raw_image_file_data[0] == 'B'
  147.                && raw_image_file_data[1] == 'M')
  148.          {
  149.             /* Get image data (24 bit), and convert to the emulated pixel format */
  150.             image_width    =
  151.                ((uint32_t) ((uint8_t)raw_image_file_data[21]) << 24) +
  152.                ((uint32_t) ((uint8_t)raw_image_file_data[20]) << 16) +
  153.                ((uint32_t) ((uint8_t)raw_image_file_data[19]) << 8) +
  154.                ((uint32_t) ((uint8_t)raw_image_file_data[18]) << 0);

  155.             image_height   =
  156.                ((uint32_t) ((uint8_t)raw_image_file_data[25]) << 24) +
  157.                ((uint32_t) ((uint8_t)raw_image_file_data[24]) << 16) +
  158.                ((uint32_t) ((uint8_t)raw_image_file_data[23]) << 8) +
  159.                ((uint32_t) ((uint8_t)raw_image_file_data[22]) << 0);
  160.             raw_image_data = (void*)malloc(image_width * image_height * 3 * sizeof(uint8_t));
  161.             if (raw_image_data)
  162.                memcpy(raw_image_data,
  163.                      raw_image_file_data + 54       * sizeof(uint8_t),
  164.                      image_width * image_height * 3 * sizeof(uint8_t));
  165.          }
  166.          /* PNG coming back from the url */
  167.          else if (raw_image_file_data[1] == 'P'
  168.                && raw_image_file_data[2] == 'N'
  169.                && raw_image_file_data[3] == 'G')
  170.          {
  171.             int retval   = 0;
  172.             rpng_t *rpng = NULL;
  173.             image_width  =
  174.                 ((uint32_t) ((uint8_t)raw_image_file_data[16]) << 24)+
  175.                 ((uint32_t) ((uint8_t)raw_image_file_data[17]) << 16)+
  176.                 ((uint32_t) ((uint8_t)raw_image_file_data[18]) << 8)+
  177.                 ((uint32_t) ((uint8_t)raw_image_file_data[19]) << 0);
  178.             image_height =
  179.                 ((uint32_t) ((uint8_t)raw_image_file_data[20]) << 24)+
  180.                 ((uint32_t) ((uint8_t)raw_image_file_data[21]) << 16)+
  181.                 ((uint32_t) ((uint8_t)raw_image_file_data[22]) << 8)+
  182.                 ((uint32_t) ((uint8_t)raw_image_file_data[23]) << 0);

  183.             if (!(rpng = rpng_alloc()))
  184.             {
  185.                error = "Can't allocate memory.";
  186.                goto finish;
  187.             }

  188.             rpng_set_buf_ptr(rpng, raw_image_file_data, (size_t)new_image_size);
  189.             rpng_start(rpng);
  190.             while (rpng_iterate_image(rpng));

  191.             do
  192.             {
  193.                retval = rpng_process_image(rpng, &raw_image_data_alpha,
  194.                      (size_t)new_image_size, &image_width, &image_height);
  195.             } while (retval == IMAGE_PROCESS_NEXT);

  196.             /* Returned output from the png processor is an upside down RGBA
  197.              * image, so we have to change that to RGB first.  This should
  198.              * probably be replaced with a scaler call.*/
  199.             {
  200.                unsigned ui;
  201.                int tw, th, tc;
  202.                int d          = 0;
  203.                raw_image_data = (void*)malloc(image_width*image_height*3*sizeof(uint8_t));
  204.                for (ui = 0; ui < image_width * image_height * 4; ui++)
  205.                {
  206.                   if (ui % 4 != 3)
  207.                   {
  208.                      tc = d % 3;
  209.                      th = image_height-d / (image_width * 3) - 1;
  210.                      tw = (d % (image_width * 3)) / 3;
  211.                      ((uint8_t*) raw_image_data)[tw * 3 + th * 3 * image_width + tc] = ((uint8_t *)raw_image_data_alpha)[ui];
  212.                      d += 1;
  213.                   }
  214.                }
  215.             }
  216.             rpng_free(rpng);
  217.          }
  218.          else
  219.          {
  220.             RARCH_LOG("Output from URL not a valid file type, or is not supported.\n");
  221.             goto finish;
  222.          }

  223.          if (!(scaler = (struct scaler_ctx*)calloc(1, sizeof(struct scaler_ctx))))
  224.             goto finish;

  225.          if (dummy_data == RETRO_HW_FRAME_BUFFER_VALID)
  226.          {
  227.             /*
  228.                In this case, we used the viewport to grab the image
  229.                and translate it, and we have the translated image in
  230.                the raw_image_data buffer.
  231.             */
  232.             RARCH_LOG("Hardware frame buffer core, but selected video driver isn't supported.\n");
  233.             goto finish;
  234.          }

  235.          /* The assigned pitch may not be reliable.  The width of
  236.             the video frame can change during run-time, but the
  237.             pitch may not, so we just assign it as the width
  238.             times the byte depth.
  239.          */

  240.          if (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
  241.          {
  242.             raw_output_data    = (uint8_t*)malloc(width * height * 4 * sizeof(uint8_t));
  243.             scaler->out_fmt    = SCALER_FMT_ARGB8888;
  244.             pitch              = width * 4;
  245.             scaler->out_stride = (int)pitch;
  246.          }
  247.          else
  248.          {
  249.             raw_output_data    = (uint8_t*)malloc(width * height * 2 * sizeof(uint8_t));
  250.             scaler->out_fmt    = SCALER_FMT_RGB565;
  251.             pitch              = width * 2;
  252.             scaler->out_stride = width;
  253.          }

  254.          if (!raw_output_data)
  255.             goto finish;

  256.          scaler->in_fmt        = SCALER_FMT_BGR24;
  257.          scaler->in_width      = image_width;
  258.          scaler->in_height     = image_height;
  259.          scaler->out_width     = width;
  260.          scaler->out_height    = height;
  261.          scaler->scaler_type   = SCALER_TYPE_POINT;
  262.          scaler_ctx_gen_filter(scaler);
  263.          scaler->in_stride     = -1 * width * 3;

  264.          scaler_ctx_scale_direct(scaler, raw_output_data,
  265.                (uint8_t*)raw_image_data + (image_height - 1) * width * 3);
  266.          video_driver_frame(raw_output_data, image_width, image_height, pitch);
  267.       }
  268.    }

  269. #ifdef HAVE_AUDIOMIXER
  270.    if (raw_sound_data)
  271.    {
  272.       audio_mixer_stream_params_t params;

  273.       params.volume               = 1.0f;
  274.       params.slot_selection_type  = AUDIO_MIXER_SLOT_SELECTION_MANUAL; /* user->slot_selection_type; */
  275.       params.slot_selection_idx   = 10;
  276.       params.stream_type          = AUDIO_STREAM_TYPE_SYSTEM; /* user->stream_type; */
  277.       params.type                 = AUDIO_MIXER_TYPE_WAV;
  278.       params.state                = AUDIO_STREAM_STATE_PLAYING;
  279.       params.buf                  = raw_sound_data;
  280.       params.bufsize              = new_sound_size;
  281.       params.cb                   = NULL;
  282.       params.basename             = NULL;

  283.       audio_driver_mixer_add_stream(&params);

  284.       if (raw_sound_data)
  285.       {
  286.          free(raw_sound_data);
  287.          raw_sound_data = NULL;
  288.       }
  289.    }
复制代码
发表于 2025-1-19 09:05 来自手机 | 显示全部楼层
看来这个API要wav 不要PCM
https://jun711.github.io/aws/convert-aws-polly-synthesized-speech-from-pcm-to-wav-format/
试试这个Python?
 楼主| 发表于 2025-1-19 18:56 | 显示全部楼层
卧槽 PCM 和 wav 还不一样?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|虎纹猫家园

GMT+8, 2025-4-26 15:23 , Processed in 0.016650 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表