由video_copy改写的颜色空间变换

/*
 *  ======== videnc_copy.c ========
 *  Video Encoder "copy" algorithm.
 *
 *  This file contains an implementation of the deprecated IVIDENC interface
 *  as defined by xDM 0.9.
 */
#include <xdc/std.h>
#include <string.h>

#include <ti/xdais/dm/ividenc.h>
#include <ti/sdo/ce/trace/gt.h>

#include <ti/sdo/ce/Engine.h>
#include <ti/sdo/ce/osal/Memory.h>
#include <ti/sdo/ce/CERuntime.h>

#include <ti/bios/include/std.h>
#include <ti/bios/include/mem.h>
#include <ti/bios/include/bcache.h>

#include "videnc_copy_ti.h"
#include "videnc_copy_ti_priv.h"
#include "cv.h"
#include "cxcore.h"

/* buffer definitions */
#define MININBUFS       1
#define MINOUTBUFS      1
#define MININBUFSIZE    1
#define MINOUTBUFSIZE   1



IplImage* pImg = NULL; 
IplImage* pCannyImg = NULL;
static Int8 *xxx = NULL;

#define SIZEOFIMG ((320)*(240)*(3)*(sizeof(char)))


extern IALG_Fxns VIDENCCOPY_TI_IALG;

#define IALGFXNS  \
		&VIDENCCOPY_TI_IALG,        /* module ID */                         \
		VIDENCCOPY_TI_activate,     /* activate */                          \
		VIDENCCOPY_TI_alloc,        /* alloc */                             \
		NULL,                       /* control (NULL => no control ops) */  \
		VIDENCCOPY_TI_deactivate,   /* deactivate */                        \
		VIDENCCOPY_TI_free,         /* free */                              \
		VIDENCCOPY_TI_initObj,      /* init */                              \
		NULL,                       /* moved */                             \
		NULL                        /* numAlloc (NULL => IALG_MAXMEMRECS) */

/*
 *  ======== VIDENCCOPY_TI_IVIDENC ========
 *  This structure defines TI's implementation of the IVIDENC interface
 *  for the VIDENCCOPY_TI module.
 */
IVIDENC_Fxns VIDENCCOPY_TI_VIDENCCOPY = {    /* module_vendor_interface */
		{IALGFXNS},
		VIDENCCOPY_TI_process,
		VIDENCCOPY_TI_control,
};


XDAS_Int16 width;
XDAS_Int16 height;
XDAS_UInt8* pResult_rgb_dsp;
XDAS_UInt8 rectCount =0;


/*
 *  ======== VIDENCCOPY_TI_IALG ========
 *  This structure defines TI's implementation of the IALG interface
 *  for the VIDENCCOPY_TI module.
 */
#ifdef _TI_
/* satisfy xDAIS symbol requirement without any overhead */
asm("_VIDENCCOPY_TI_IALG .set _VIDENCCOPY_TI_VIDENCCOPY");

#else

/*
 *  We duplicate the structure here to allow this code to be compiled and
 *  run non-DSP platforms at the expense of unnecessary data space
 *  consumed by the definition below.
 */
IALG_Fxns VIDENCCOPY_TI_IALG = {      /* module_vendor_interface */
		IALGFXNS
};

#endif

/* tracing information */
#define GTNAME "ti.sdo.ce.examples.codecs.videnc_copy"
static GT_Mask curTrace = {NULL,NULL};

/*
 *  ======== VIDENCCOPY_TI_activate ========
 */
Void VIDENCCOPY_TI_activate(IALG_Handle handle) ///typedef struct IALG_Obj *IALG_Handle;
{
	GT_1trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_activate(0x%x)\n", handle);
}


/*
 *  ======== VIDENCCOPY_TI_deactivate ========
 */
Void VIDENCCOPY_TI_deactivate(IALG_Handle handle)
{
	GT_1trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_deactivate(0x%x)\n", handle);
}


/*
 *  ======== VIDENCCOPY_TI_alloc ========
 */
Int VIDENCCOPY_TI_alloc(const IALG_Params *algParams,IALG_Fxns **pf, IALG_MemRec memTab[])///IALG_Params 
{
	if (curTrace.modName == NULL)
	{   /* initialize GT (tracing) */
		GT_create(&curTrace, GTNAME);
	}

	GT_3trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_alloc(0x%x, 0x%x, 0x%x)\n",algParams, pf, memTab);

	/* Request memory for my object */
	memTab[0].size = sizeof(VIDENCCOPY_TI_Obj);
	memTab[0].alignment = 0;
	memTab[0].space = IALG_EXTERNAL;
	memTab[0].attrs = IALG_PERSIST;
	//采集到的数据
	memTab[1].size = SIZEOFIMG;
	memTab[1].alignment = 0;
	memTab[1].space = IALG_EXTERNAL;
	memTab[1].attrs = IALG_PERSIST;


	//img_opencv =cvCreateImage(cvSize(320,240),8,3);


	return (2);
}





/*
 *  ======== VIDENCCOPY_TI_initObj ========
 */
Int VIDENCCOPY_TI_initObj(IALG_Handle handle,const IALG_MemRec memTab[], IALG_Handle p,const IALG_Params *algParams)
{
	GT_4trace(curTrace, GT_ENTER,"VIDENCCOPY_TI_initObj(0x%x, 0x%x, 0x%x, 0x%x)\n", handle, memTab,p, algParams);

	pResult_rgb_dsp =(unsigned char *) memTab[1].base;

	return (IALG_EOK);
}


/*
 *  ======== VIDENCCOPY_TI_process ========
 */
XDAS_Int32 VIDENCCOPY_TI_process(IVIDENC_Handle h, XDM_BufDesc *inBufs,XDM_BufDesc *outBufs, IVIDENC_InArgs *inArgs, IVIDENC_OutArgs *outArgs)
{
	XDAS_Int32 curBuf;
	XDAS_UInt32 minSamples;
	int i,j;
	int  width,height;
	unsigned char * ptr;
	unsigned char *temp;

	GT_5trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_process(0x%x, 0x%x, 0x%x, ""0x%x, 0x%x)\n", h, inBufs, outBufs, inArgs, outArgs);

	/* validate arguments - this codec only supports "base" xDM. */
	if ((inArgs->size != sizeof(*inArgs)) ||(outArgs->size != sizeof(*outArgs))) 
	{
		GT_2trace(curTrace, GT_ENTER,"VIDENCCOPY_TI_process, unsupported size ""(0x%x, 0x%x)\n", inArgs->size, outArgs->size);
		return (IVIDENC_EFAIL);
	}


	/* outArgs->bytesGenerated reports the total number of bytes generated */
	outArgs->bytesGenerated = 0;

	/*
	 * A couple constraints for this simple "copy" codec:
	 *    - Video encoding presumes a single input buffer, so only one input
	 *      buffer will be encoded, regardless of inBufs->numBufs.
	 *    - Given a different size of an input and output buffers, only
	 *      encode (i.e., copy) the lesser of the sizes.
	 */



	for (curBuf = 0; (curBuf < inBufs->numBufs) &&(curBuf < outBufs->numBufs); curBuf++)
	{

		/* there's an available in and out buffer, how many samples? */
		minSamples = inBufs->bufSizes[curBuf] < outBufs->bufSizes[curBuf] ? inBufs->bufSizes[curBuf] : outBufs->bufSizes[curBuf];

		//
#if 0
		YuyvToY_dsp((unsigned char *)inBufs->bufs[curBuf], (unsigned char *)buf_dsp_x, 320,240);

		for(i =0; i < 240; i++)
			for(j =0; j < 160; j++)  
			{
				//*((unsigned char *)buf_dsp_x+ i*320+ j) = 0x80;
				//*((unsigned char *)buf_dsp+ i*640+ j) = 0x80;
			}
		YtoRGB((unsigned char *)outBufs->bufs[curBuf], (unsigned char *)buf_dsp_x, 320,240);
#endif

		// convert_dsp(inBufs->bufs[curBuf],outBufs->bufs[curBuf],320, 240);
		//convert(inBufs->bufs[curBuf], outBufs->bufs[curBuf], 320, 240);
		// memcpy(outBufs->bufs[curBuf], inBufs->bufs[curBuf], minSamples);

		//YUVToRGB24((unsigned char *)inBufs->bufs[curBuf],(unsigned char *)outBufs->bufs[curBuf], 320, 240);

		//

		//#ifdef USE_ACPY3
#if 0

		thisTransferSrcAddr        = (Uint32)inBufs->bufs[curBuf];
		thisTransferDstAddr        = (Uint32)outBufs->bufs[curBuf];
		remainingTransferChunkSize = minSamples;

		while (remainingTransferChunkSize > 0) {

			if (remainingTransferChunkSize > maxTransferChunkSize) {
				thisTransferChunkSize = maxTransferChunkSize;
			}
			else {
				thisTransferChunkSize = remainingTransferChunkSize;
			}

			/* Configure the logical channel */
			params.transferType = ACPY3_1D1D;
			params.srcAddr      = (void *)thisTransferSrcAddr;
			params.dstAddr      = (void *)thisTransferDstAddr;
			params.elementSize  = thisTransferChunkSize;
			params.numElements  = 1;
			params.waitId       = 0;
			params.numFrames    = 1;

			remainingTransferChunkSize -= thisTransferChunkSize;
			thisTransferSrcAddr += thisTransferChunkSize;
			thisTransferDstAddr += thisTransferChunkSize;

			/* Configure logical dma channel */
			ACPY3_configure(videncObj->dmaHandle1D1D8B, ?ms, 0);

			/* Use DMA to copy data */
			ACPY3_start(videncObj->dmaHandle1D1D8B);

			/* wait for transfer to finish  */
			ACPY3_wait(videncObj->dmaHandle1D1D8B);
		}
		GT_1trace(curTrace, GT_2CLASS, "VIDENCCOPY_TI_process> "
				"ACPY3 Processed %d bytes.\n", minSamples);
#else
		GT_3trace(curTrace, GT_2CLASS, "VIDENCCOPY_TI_process> ""memcpy (0x%x, 0x%x, %d)\n",outBufs->bufs[curBuf], inBufs->bufs[curBuf], minSamples);

		/* process the data: read input, produce output */


		//YUVToRGB24((unsigned char *)inBufs->bufs[curBuf],(unsigned char *)outBufs->bufs[curBuf], 320, 240);

		// ptr = (unsigned char *)pImg->imageData
#if 0
		for(i = 0; i <120; i++){
			ptr =(unsigned char *)(pImg->imageData + i*3*320);
			for(j = 0; j <320; j++){
				*( ptr+3*j + 0) = 80;
				*( ptr+3*j + 1)  = 80;
				*( ptr+3*j + 2)  = 80;
			}
		}

		//cvCanny(pImg, pCannyImg, 50, 150, 3);
		memcpy( (unsigned char *)outBufs->bufs[curBuf],(unsigned char *)pImg->imageData, 320*240*3);
#else



		//cvCanny(pImg, pCannyImg, 50, 150, 3);
		//memcpy( (unsigned char *)outBufs->bufs[curBuf],(unsigned char *)pImg->imageData, 320*240*3);
		//temp = (unsigned char *)malloc(320 * 240 *3);
		//temp = (unsigned char *)pResult_rgb_dsp;
		//temp = (unsigned char *)Memory_contigAlloc(320*240*3,8);
		// temp = (unsigned char *)myMemalign(320*240*3,8);

		pImg = cvCreateImage(cvSize(320,240),8,3); 
		pCannyImg = cvCreateImage(cvSize(320,240),8,3);




		memcpy((unsigned char *)pImg->imageData, (unsigned char *)inBufs->bufs[curBuf], 320*240*3);

		for(i = 0; i <120; i++){
			ptr =((unsigned char *)pImg->imageData+i*3*320);
			for(j = 0; j < 320; j++){

				ptr[3*j + 0] = 255;
				ptr[3*j + 1] = 255;
				ptr[3*j + 2] = 255;
			}
		}


		//  cvCanny(pImg, pCannyImg, 50, 150, 3);
		cvLine( pImg, cvPoint(15,15), cvPoint(75,15), CV_RGB(255, 0, 0), 3 ,1,0 );
		cvLine( pImg, cvPoint(75,15), cvPoint(75,75), CV_RGB(255, 0, 0), 3 ,1,0 );
		cvRectangle(pImg, cvPoint(75,75), cvPoint(120,120), CV_RGB(0, 255, 0), 3, 1, 0);
		memcpy((unsigned char *)outBufs->bufs[curBuf], (unsigned char *)pImg->imageData, minSamples);
		//memcpy(outBufs->bufs[curBuf], temp, minSamples);
#endif
		//memcpy(outBufs->bufs[curBuf], inBufs->bufs[curBuf], minSamples);
#endif
		//Memory_contigFree(temp,320*240*3);
		cvReleaseImage(&pImg);
		cvReleaseImage(&pCannyImg);
		outArgs->bytesGenerated += minSamples;
	}

	/* Fill out the rest of the outArgs struct */
	outArgs->extendedError = 0;
	outArgs->encodedFrameType = 0;    /* TODO */
	outArgs->inputFrameSkip = IVIDEO_FRAME_ENCODED;
	outArgs->reconBufs.numBufs = 0;   /* important: indicate no reconBufs */

	return (IVIDENC_EOK);
}


/*
 *  ======== VIDENCCOPY_TI_control ========
 */
XDAS_Int32 VIDENCCOPY_TI_control(IVIDENC_Handle handle, IVIDENC_Cmd id,
		IVIDENC_DynamicParams *params, IVIDENC_Status *status)
{
	XDAS_Int32 retVal;

	GT_4trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_control(0x%x, 0x%x, 0x%x, ""0x%x)\n", handle, id, params, status);

	/* validate arguments - this codec only supports "base" xDM. */
	if ((params->size != sizeof(*params)) ||
			(status->size != sizeof(*status))) {

		GT_2trace(curTrace, GT_ENTER,"VIDENCCOPY_TI_control, unsupported size ""(0x%x, 0x%x)\n", params->size, status->size);

		return (IVIDENC_EFAIL);
	}

	switch (id) {
	case XDM_GETSTATUS:
	case XDM_GETBUFINFO:
		status->extendedError = 0;

		status->bufInfo.minNumInBufs = MININBUFS;
		status->bufInfo.minNumOutBufs = MINOUTBUFS;
		status->bufInfo.minInBufSize[0] = MININBUFSIZE;
		status->bufInfo.minOutBufSize[0] = MINOUTBUFSIZE;

		retVal = IVIDENC_EOK;

		break;

	case XDM_SETPARAMS:
	case XDM_SETDEFAULT:
	case XDM_RESET:
	case XDM_FLUSH:
		/* TODO - for now just return success. */

		retVal = IVIDENC_EOK;
		break;

	default:
		/* unsupported cmd */
		retVal = IVIDENC_EFAIL;

		break;
	}

	return (retVal);
}

/*
 *  ======== VIDENCCOPY_TI_free ========
 */
Int VIDENCCOPY_TI_free(IALG_Handle handle, IALG_MemRec memTab[])
{
	GT_2trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_free(0x%lx, 0x%lx)\n",handle, memTab);

	VIDENCCOPY_TI_alloc(NULL, NULL, memTab);

	memTab[1].size = SIZEOFIMG;
	memTab[1].alignment = 0;
	memTab[1].space = IALG_EXTERNAL;
	memTab[1].attrs = IALG_PERSIST;
	memTab[1].base = pResult_rgb_dsp;
	//free(pResult_rgb_dsp);

	//cvReleaseImage(&img_opencv);

	return (2);
}

#if 0
CV_IMPL  void*  cvAlloc( size_t size )
						{

	CV_FUNCNAME( "cvAlloc" );

	//IALG_MemRec *memTab = malloc( sizeof(IALG_MemRec));
	void * ptr;

	__BEGIN__;

	ptr= (void *)malloc(size);


	__END__;

	return  ptr;
						}


CV_IMPL  void  cvFree_( void* ptr )
{
	CV_FUNCNAME( "cvFree_" );

	__BEGIN__;

	free( ptr );

	__END__;
}
#endif

static unsigned char buf_dsp_x[320*240*2];
static unsigned char image_Y_dsp_x[320*240*2];

inline void yuv_to_rgb16_dsp(unsigned char y,unsigned char u,unsigned char v,unsigned char *rgb)
{
	register int r,g,b;
	int rgb16;

	r = (1192 * (y - 16) + 1634 * (v - 128) ) >> 10;
	g = (1192 * (y - 16) - 833 * (v - 128) - 400 * (u -128) ) >> 10;
	b = (1192 * (y - 16) + 2066 * (u - 128) ) >> 10;

	r = r > 255 ? 255 : r < 0 ? 0 : r;
	g = g > 255 ? 255 : g < 0 ? 0 : g;
	b = b > 255 ? 255 : b < 0 ? 0 : b;

	rgb16 = (int)(((r >> 3)<<11) | ((g >> 2) << 5)| ((b >> 3) << 0));

	*rgb = (unsigned char)(rgb16 & 0xFF);
	rgb++;
	*rgb = (unsigned char)((rgb16 & 0xFF00) >> 8);
}

void convert(unsigned char *buf, unsigned char *rgb, int width, int height) {
	int x, y, z = 0;
	int blocks;

	blocks = (width * height) * 2;

	for (y = 0; y < blocks; y += 4) {
		unsigned char Y1, Y2, U, V;

		Y1 = buf[y + 0];
		U = buf[y + 1];
		Y2 = buf[y + 2];
		V = buf[y + 3];

		yuv_to_rgb16_dsp(Y1, U, V, &rgb[y]);
		yuv_to_rgb16_dsp(Y2, U, V, &rgb[y + 2]);
	}
}

void YtoRGB(unsigned char *Outrgb, unsigned char *pSrcbuf, int width, int height)
{


	int x,y,z=0;
	int blocks;

	blocks = (width * height) * 2;

	for (y = 0; y < blocks; y+=4) {
		unsigned char Y1, Y2, U, V;

		///
		Y1 =*pSrcbuf;
		pSrcbuf++;

		Y2 =*pSrcbuf;
		pSrcbuf++;

		yuv_to_rgb16_dsp(Y1, 0x80, 0x80, &Outrgb[y]);
		yuv_to_rgb16_dsp(Y2, 0x80, 0x80, &Outrgb[y + 2]);
	}



}

#define Memory_DEFAULTALIGNMENT ((xdc_UInt)(-1))



void convert_dsp(unsigned char *buf, unsigned char *rgb, int width, int height)
{
	int x,y,z=0;
	int blocks;

	blocks = (width * height) * 2;

	for (y = 0; y < blocks; y+=4) {
		unsigned char Y1, Y2, U, V;

		///
		Y1 = buf[y + 0];
		U = buf[y + 1];
		Y2 = buf[y + 2];
		V = buf[y + 3];
		//

		yuv_to_rgb16_dsp(Y1, U, V, &rgb[y]);
		yuv_to_rgb16_dsp(Y2, U, V, &rgb[y + 2]);
		//yuv_to_rgb16(Y1, 0x80, 0x80, &rgb[y]);
		//yuv_to_rgb16(Y2, 0x80, 0x80, &rgb[y + 2]);
	}
}

#if 1
void YuyvToY_dsp(unsigned char *Srbuf, unsigned char *pDstbuf, int width, int height)
{


	int x,y,z=0;
	int blocks;

	blocks = (width * height) * 2;

	for (y = 0; y < blocks; y+=4) {
		///
		*pDstbuf =  Srbuf[y + 0];
		pDstbuf++;
		*pDstbuf = Srbuf[y+2];
		pDstbuf++;
	}
}
#endif



inline void yuv_to_rgb24(unsigned char y, unsigned char u, unsigned char v,
		unsigned char *rgb) {

	register int r, g, b;


	r = (1192 * (y - 16) + 1634 * (v - 128)) >> 10;
	g = (1192 * (y - 16) - 833 * (v - 128) - 400 * (u - 128)) >> 10;
	b = (1192 * (y - 16) + 2066 * (u - 128)) >> 10;

	r = r > 255 ? 255 : r < 0 ? 0 : r;
	g = g > 255 ? 255 : g < 0 ? 0 : g;
	b = b > 255 ? 255 : b < 0 ? 0 : b;

	*rgb = r;
	rgb++;
	*rgb = g;
	rgb++;
	*rgb = b;



#if 0
	rgb16 = (int) (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0));

	*rgb = (unsigned char) (rgb16 & 0xFF);
	rgb++;
	*rgb = (unsigned char) ((rgb16 & 0xFF00) >> 8);
#endif
}


void YUVToRGB24(unsigned char *buf, unsigned char *rgb, int width, int height) {


	int  y = 0;
	int j = 0;
	int blocks;

	blocks = (width * height) * 2;


	for (y = 0; y < blocks; y += 4) {
		unsigned char Y1, Y2, U1, V1;

		Y1 = buf[y + 0];
		U1 = buf[y + 1];
		Y2 = buf[y + 2];
		V1 = buf[y + 3];


		yuv_to_rgb24(Y1, U1, V1, &rgb[j]);
		yuv_to_rgb24(Y2, U1, V1, &rgb[j + 3]);
		j +=6;
	}

}

void YUVToRGB24_8(unsigned char *buf, unsigned char *rgb, int width, int height) {


	int  y = 0;
	int j = 0;
	int blocks;

	blocks = (width * height) * 2;


	for (y = 0; y < blocks; y += 8) {
		unsigned char Y1, Y2, U1, V1;
		unsigned char Y1_1, Y2_1, U1_1, V1_1;

		Y1 = buf[y + 0];
		U1 = buf[y + 1];
		Y2 = buf[y + 2];
		V1 = buf[y + 3];

		// V1 = buf[y + 1];
		//U1 = buf[y + 3];

		Y1_1 = buf[y + 4];
		U1_1 = buf[y + 5];
		Y2_1 = buf[y + 6];
		V1_1 = buf[y + 7];

		// V1_1 = buf[y + 7];
		// U1_1 = buf[y + 5];




		yuv_to_rgb24(Y1, U1, V1, &rgb[j]);
		yuv_to_rgb24(Y2, U1, V1, &rgb[j + 3]);

		yuv_to_rgb24(Y1_1, U1_1, V1_1, &rgb[j + 6]);
		yuv_to_rgb24(Y2_1, U1_1, V1_1, &rgb[j + 9]);
		j +=12;
	}

}

static Ptr myMemalign(UInt32 size, UInt32 align)
{
	UInt32     alignSize;
	UInt32     alignBytes;
	UInt32     remainBytes;
	Ptr        buf;
	Ptr        alignBuf;
	UInt32     tmpAlign;
	UInt32    *addrPtr;


	/*
	 *  Must at least align on 32-bit boundary since we're storing the
	 *  32-bit address of the malloc'd buffer.
	 */
	alignBytes = (align < sizeof(UInt32)) ? sizeof(UInt32) : align;

	/*
	 *  We will allocate a buffer larger than "size", to allow for alignment
	 *  and to store the address and original size of the buffer returned by
	 *  malloc() at the end of the buffer.
	 *  Make size a multiple of 32-bits so it will be easier to find the
	 *  address of the buffer returned by malloc(). 
	 */
	alignSize = size;
	if ((remainBytes = alignSize & (sizeof(UInt32) - 1)) != 0) {
		/* size is not a multiple of 32-bits */
		alignSize += sizeof(UInt32) - remainBytes;
		remainBytes = sizeof(UInt32) - remainBytes;
	}

	/* Add 2 32-bit words to store address and original size of buffer */
	alignSize += sizeof(UInt32) * 2;

	alignSize += alignBytes;

	/* malloc the buffer! */
	if ((buf = malloc(alignSize)) == NULL) {
		return (NULL);
	}

	/* Get the aligned address */
	tmpAlign = (UInt32)buf & (alignBytes - 1);
	if (tmpAlign) {
		alignBuf = (Void *)((UInt32)buf + alignBytes - tmpAlign);
	}
	else {
		/* The buffer was already aligned */
		alignBuf = buf;
	}

	/* Store the malloc'd address and original size for freeing later. */
	addrPtr = (UInt32 *)((UInt32)alignBuf + size + remainBytes);
	*addrPtr = (UInt32)buf;
	*(addrPtr + 1) = alignSize;

	return (alignBuf);
}

/*

/*
 *  @(#) ti.sdo.ce.examples.codecs.videnc_copy; 1, 0, 0,262; 12-2-2010 21:23:15; /db/atree/library/trees/ce/ce-r11x/src/ xlibrary

 */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值