static int video_ps3_vdec_codec_create(media_codec_t *mc, const media_codec_params_t *mcp, media_pipe_t *mp) { vdec_decoder_t *vdd; struct vdec_type dec_type = {0}; struct vdec_attr dec_attr = {0}; int spu_threads; int r; switch(mc->codec_id) { case AV_CODEC_ID_MPEG2VIDEO: if(!vdec_mpeg2_loaded) return no_lib(mp, "MPEG-2"); dec_type.codec_type = VDEC_CODEC_TYPE_MPEG2; dec_type.profile_level = VDEC_MPEG2_MP_HL; spu_threads = 1; break; case AV_CODEC_ID_H264: if(mcp != NULL) { if(mcp->profile == FF_PROFILE_H264_CONSTRAINED_BASELINE) return 1; // can't play this if(mcp->profile >= FF_PROFILE_H264_HIGH_10) return 1; // No 10bit support if(mcp->extradata != NULL) { h264_parser_t hp; hexdump("extradata", mcp->extradata, mcp->extradata_size); if(h264_parser_init(&hp, mcp->extradata, mcp->extradata_size)) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Cell-h264: Broken headers, Disabling acceleration")); return -1; } TRACE(TRACE_DEBUG, "VDEC", "Dumping SPS"); int too_big_refframes = 0; for(int i = 0; i < H264_PARSER_NUM_SPS; i++) { const h264_sps_t *s = &hp.sps_array[i]; if(!s->present) continue; TRACE(TRACE_DEBUG, "VDEC", "SPS[%d]: %d x %d profile:%d level:%d.%d ref-frames:%d", i, s->mb_width * 16, s->mb_height * 16, s->profile, s->level / 10, s->level % 10, s->num_ref_frames); if(s->mb_height >= 68 && s->num_ref_frames > 4) too_big_refframes = s->num_ref_frames; } h264_parser_fini(&hp); if(too_big_refframes) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Cell-h264: %d Ref-frames for 1080 content is incompatible with PS3 HW decoder. Disabling acceleration"), too_big_refframes); return -1; } } } if(!vdec_h264_loaded) return no_lib(mp, "h264"); dec_type.codec_type = VDEC_CODEC_TYPE_H264; if(mcp != NULL && mcp->level > 42) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Cell-h264: Forcing level 4.2 for content in level %d.%d. This may break video playback."), mcp->level / 10, mcp->level % 10); } dec_type.profile_level = 42; spu_threads = 4; break; default: return 1; } r = vdec_query_attr(&dec_type, &dec_attr); if(r) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Unable to query Cell codec. Error 0x%x"), r); return 1; } vdd = calloc(1, sizeof(vdec_decoder_t)); #define ROUND_UP(p, round) ((p + round - 1) & ~(round - 1)) size_t allocsize = ROUND_UP(dec_attr.mem_size, 1024*1024); u32 taddr; if(Lv2Syscall3(348, allocsize, 0x400, (u64)&taddr)) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Unable to open Cell codec. Unable to allocate %d bytes of RAM"), dec_attr.mem_size); return 1; } vdd->mem = (void *)(uint64_t)taddr; TRACE(TRACE_DEBUG, "VDEC", "Opening codec %s level %d using %d bytes of RAM", mc->codec_id == AV_CODEC_ID_H264 ? "h264" : "MPEG2", dec_type.profile_level, dec_attr.mem_size); vdd->config.mem_addr = (intptr_t)vdd->mem; vdd->config.mem_size = dec_attr.mem_size; vdd->config.num_spus = spu_threads; vdd->config.ppu_thread_prio = VDEC_PPU_PRIO; vdd->config.spu_thread_prio = VDEC_SPU_PRIO; vdd->config.ppu_thread_stack_size = 1 << 14; vdec_closure c; c.fn = (intptr_t)OPD32(decoder_callback); c.arg = (intptr_t)vdd; r = vdec_open(&dec_type, &vdd->config, &c, &vdd->handle); if(r) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Unable to open Cell codec. Error 0x%x"), r); Lv2Syscall1(349, (uint64_t)vdd->mem); free(vdd); return 1; } if(mcp != NULL) { vdd->level_major = mcp->level / 10; vdd->level_minor = mcp->level % 10; } if(mc->codec_id == AV_CODEC_ID_H264 && mcp != NULL && mcp->extradata_size) h264_to_annexb_init(&vdd->annexb, mcp->extradata, mcp->extradata_size); vdd->max_order = -1; hts_mutex_init(&vdd->mtx); hts_cond_init(&vdd->audone, &vdd->mtx); hts_cond_init(&vdd->seqdone, &vdd->mtx); TRACE(TRACE_DEBUG, "VDEC", "Cell accelerated codec created using %d bytes of RAM", dec_attr.mem_size); mc->opaque = vdd; mc->decode = decoder_decode; mc->flush = decoder_flush; mc->close = decoder_close; vdec_start_sequence(vdd->handle); return 0; }
static int video_ps3_vdec_codec_create(media_codec_t *mc, const media_codec_params_t *mcp, media_pipe_t *mp) { vdec_decoder_t *vdd; struct vdec_type dec_type = {0}; struct vdec_attr dec_attr = {0}; int spu_threads; int r; switch(mc->codec_id) { case CODEC_ID_MPEG2VIDEO: if(!vdec_mpeg2_loaded) return no_lib(mp, "MPEG-2"); dec_type.codec_type = VDEC_CODEC_TYPE_MPEG2; dec_type.profile_level = VDEC_MPEG2_MP_HL; spu_threads = 1; break; case CODEC_ID_H264: if(mcp != NULL && mcp->profile == FF_PROFILE_H264_CONSTRAINED_BASELINE) return 1; // can't play this if(!vdec_h264_loaded) return no_lib(mp, "h264"); dec_type.codec_type = VDEC_CODEC_TYPE_H264; if(mcp != NULL && mcp->level > 42) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Cell-h264: Forcing level 4.2 for content in level %d.%d. This may break video playback."), mcp->level / 10, mcp->level % 10); } dec_type.profile_level = 42; spu_threads = 4; break; default: return 1; } r = vdec_query_attr(&dec_type, &dec_attr); if(r) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Unable to query Cell codec. Error 0x%x"), r); return 1; } vdd = calloc(1, sizeof(vdec_decoder_t)); #define ROUND_UP(p, round) ((p + round - 1) & ~(round - 1)) size_t allocsize = ROUND_UP(dec_attr.mem_size, 1024*1024); u32 taddr; if(Lv2Syscall3(348, allocsize, 0x400, (u64)&taddr)) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Unable to open Cell codec. Unable to allocate %d bytes of RAM"), dec_attr.mem_size); return 1; } vdd->mem = (void *)(uint64_t)taddr; TRACE(TRACE_DEBUG, "VDEC", "Opening codec %s level %d using %d bytes of RAM", mc->codec_id == CODEC_ID_H264 ? "h264" : "MPEG2", dec_type.profile_level, dec_attr.mem_size); vdd->config.mem_addr = (intptr_t)vdd->mem; vdd->config.mem_size = dec_attr.mem_size; vdd->config.num_spus = spu_threads; vdd->config.ppu_thread_prio = VDEC_PPU_PRIO; vdd->config.spu_thread_prio = VDEC_SPU_PRIO; vdd->config.ppu_thread_stack_size = 1 << 14; vdec_closure c; c.fn = (intptr_t)OPD32(decoder_callback); c.arg = (intptr_t)vdd; r = vdec_open(&dec_type, &vdd->config, &c, &vdd->handle); if(r) { notify_add(mp->mp_prop_notifications, NOTIFY_WARNING, NULL, 10, _("Unable to open Cell codec. Error 0x%x"), r); Lv2Syscall1(349, (uint64_t)vdd->mem); free(vdd); return 1; } if(mcp != NULL) { vdd->level_major = mcp->level / 10; vdd->level_minor = mcp->level % 10; } if(mc->codec_id == CODEC_ID_H264 && mcp != NULL && mcp->extradata_size) h264_to_annexb_init(&vdd->annexb, mcp->extradata, mcp->extradata_size); vdd->max_order = -1; hts_mutex_init(&vdd->mtx); hts_cond_init(&vdd->audone, &vdd->mtx); hts_cond_init(&vdd->seqdone, &vdd->mtx); TRACE(TRACE_DEBUG, "VDEC", "Cell accelerated codec created using %d bytes of RAM", dec_attr.mem_size); mc->opaque = vdd; mc->decode = decoder_decode; mc->flush = decoder_flush; mc->close = decoder_close; vdec_start_sequence(vdd->handle); return 0; }