当前位置: 首页 > 编程日记 > 正文

基于libmad库的MP3解码简析

基于libmad库的MP3解码简析
 MAD (libmad)是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3)。LIBMAD 提供 24-bit 的 PCM 输出,完全是定点计算,非常适合没有浮点支持的平台上使用。使用 libmad 提供的一系列 API,就可以非常简单地实现 MP3 数据解码工作。在 libmad 的源代码文件目录下的 mad.h 文件中,可以看到绝大部分该库的数据结构和 API 等。
     网上有很多关于libmad的使用实例,在他们的基础上,我稍加总结、整理和衍生,文末给出相关参考链接,表示感谢!
     一、libmad库源码
     可以去相关网站下载,给出链接:
     http://download.chinaunix.net/download.php?id=11891&ResourceID=5910
可以根据不同的平台自行编译或者移植,略述。
     二、相关数据结构及函数接口简介
     1、struct mad_decode
  1. struct mad_decoder {
  2. enum mad_decoder_mode mode;

  3. int options;

  4. struct {
  5. long pid;
  6. int in;
  7. int out;
  8. } async;

  9. struct {
  10. struct mad_stream stream;
  11. struct mad_frame frame;
  12. struct mad_synth synth;
  13. } *sync;

  14. void *cb_data;

  15. enum mad_flow (*input_func)(void *, struct mad_stream *);
  16. enum mad_flow (*header_func)(void *, struct mad_header const *);
  17. enum mad_flow (*filter_func)(void *,
  18. struct mad_stream const *, struct mad_frame *);
  19. enum mad_flow (*output_func)(void *,
  20. struct mad_header const *, struct mad_pcm *);
  21. enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
  22. enum mad_flow (*message_func)(void *, void *, unsigned int *);
  23. };
2、struct mad_stream

  1. struct mad_stream {
  2.  unsigned char const *buffer;        /* input bitstream buffer */
  3.   unsigned char const *bufend;        /* end of buffer */
  4. unsigned long skiplen;              /* bytes to skip before next frame */

  5. int sync;                           /* stream sync found */
  6. unsigned long freerate;             /* free bitrate (fixed) */

  7.   unsigned char const *this_frame;    /* start of current frame */
  8.   unsigned char const *next_frame;    /* start of next frame */
  9. struct mad_bitptr ptr;              /* current processing bit pointer */

  10. struct mad_bitptr anc_ptr;          /* ancillary bits pointer */
  11. unsigned int anc_bitlen;            /* number of ancillary bits */

  12. unsigned char (*main_data)[MAD_BUFFER_MDLEN];
  13. /* Layer III main_data() */
  14. unsigned int md_len;                /* bytes in main_data */

  15. int options;                        /* decoding options (see below) */
  16. enum mad_error error;               /* error code (see above) */
  17. };

     三、MP3解码流程简介
MP3解码有同步方式和异步方式两种,libmad是以桢为单位对MP3进行解码的,所谓同步方式是指解码函数在解码完一帧后才返回并带回出错信息,异步方式是指解码函数在调用后立即返回,通过消息传递解码状态信息。
1、首先创建一个解码器 struct mad_decoder decoder,紧接着调用函数  mad_decoder_init(...)函数,给出这个函数的原型及定义

  1. /*
  2. * NAME:    decoder->init()
  3. * DESCRIPTION:    initialize a decoder object with callback routines
  4. */
  5. void mad_decoder_init(struct mad_decoder *decoder, void *data,
  6. enum mad_flow (*input_func)(void *,
  7. struct mad_stream *),
  8. enum mad_flow (*header_func)(void *,
  9. struct mad_header const *),
  10. enum mad_flow (*filter_func)(void *,
  11. struct mad_stream const *,
  12. struct mad_frame *),
  13. enum mad_flow (*output_func)(void *,
  14. struct mad_header const *,
  15. struct mad_pcm *),
  16. enum mad_flow (*error_func)(void *,
  17. struct mad_stream *,
  18. struct mad_frame *),
  19. enum mad_flow (*message_func)(void *,
  20. void *, unsigned int *))
  21. {
  22. decoder->mode = -1;

  23. decoder->options = 0;

  24. decoder->async.pid = 0;
  25. decoder->async.in = -1;
  26. decoder->async.out = -1;

  27. decoder->sync = 0;

  28. decoder->cb_data = data;

  29. decoder->input_func = input_func;
  30. decoder->header_func = header_func;
  31. decoder->filter_func = filter_func;
  32. decoder->output_func = output_func;
  33. decoder->error_func = error_func;
  34. decoder->message_func = message_func;
  35. }
用户编程可以用如下方式调用,可以看到从第三个参数开始,其实都是一些列的函数指针,这里初始化的目的其实是给创建的decoder注册下面即将要自己实现的这些函数。Libmad库会在解码过程中回调这些函数:

  1. mad_decoder_init(&decoder, &buffer,
  2. input, 0 /* header */, 0 /* filter */, output,
  3. error, 0 /* message */);
第一个参数,就是定义的解码器decoder;
第二个参数,是一个void型的函数指针,这里也就是给你的用户空间定义私有的数据结构体用的,下面会给出具体的例子来说明其用法;
第三个参数,input_func函数,这个是用来读取你的mp3资源的函数;
第四个参数,header_func函数,这个顾名思义是处理mp3头部信息的函数,可以根据需要取舍;
第五个参数,filter_func函数,也没有深入理解过,可以不必实现;
     第六个参数,output_func函数,这个是用来将解码之后的数据写入输出缓冲区或者音频设备节点的;
     第七个参数,error_func函数,是用来打印返回的解码出错信息的;
     第八个参数,message_func可以不必实现。

     2、调用mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC)函数启动解码,查看Libmad库源码可知,这个函数里面会注册一个函数指针
  1. /*
  2. * NAME:    decoder->run()
  3. * DESCRIPTION:    run the decoder thread either synchronously or asynchronously
  4. */
  5. int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode)
  6. {
  7. int result;
  8. int (*run)(struct mad_decoder *) = 0;

  9. switch (decoder->mode = mode) {
  10.   case MAD_DECODER_MODE_SYNC:
  11.     run = run_sync; 
  12.     break;

  13. case MAD_DECODER_MODE_ASYNC:
  14. if defined(USE_ASYNC)
  15. run = run_async;
  16. # endif
  17. break;
  18. }

  19. if (run == 0)
  20. return -1;

  21. decoder->sync = malloc(sizeof(*decoder->sync));
  22. if (decoder->sync == 0)
  23. return -1;

  24.   result = run(decoder);

  25. free(decoder->sync);
  26. decoder->sync = 0;

  27. return result;
  28. }
而在这个run_sync(struct mad_decoder *decoder)函数中则有一个大的while循环来依次调用
decoder->input_func(decoder->cb_data, stream)获取mp3源文件,然后交由相关库函数解码。
而后会有decoder->output_func(decoder->cb_data,  &frame->header, &synth->pcm)函数来输出解码后的数据。
     3、最后调用mad_decoder_finish(&decoder)结束解码,释放decoder资源。
     4、在input_func函数中,会调用一个很重要的函数
mad_stream_buffer(stream, buffer->start, buffer->length) ,第一个参数指向一个mad_stream变量,mad_stream结构定义在stream.h头文件里,用于记录文件的地址和当前处理的位置。第二、三个参数分别是mp3文件在内存中映像的起始地址和文件长度。mad_stream_buffer()函数将mp3文件与mad_stream结构进行关联。
     四、MP3解码编程实例

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/stat.h>
  6. #include <sys/mman.h>
  7. #include <fcntl.h>
  8. #include <sys/types.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/soundcard.h>
  11. #include "mad.h"

  12. #define BUFSIZE 8192

  13. /*
  14. * This is a private message structure. A generic pointer to this structure
  15. * is passed to each of the callback functions. Put here any data you need
  16. * to access from within the callbacks.
  17. */
  18. struct buffer {
  19. FILE *fp; /*file pointer*/
  20. unsigned int flen; /*file length*/
  21. unsigned int fpos; /*current position*/
  22. unsigned char fbuf[BUFSIZE]; /*buffer*/
  23. unsigned int fbsize; /*indeed size of buffer*/
  24. };
  25. typedef struct buffer mp3_file;

  26. int soundfd; /*soundcard file*/
  27. unsigned int prerate = 0; /*the pre simple rate*/

  28. int writedsp(int c)
  29. {
  30. return write(soundfd, (char *)&c, 1);
  31. }

  32. void set_dsp()
  33. {
  34. #if 0
  35. int format = AFMT_S16_LE;
  36. int channels = 2;
  37. int rate = 44100;

  38. soundfd = open("/dev/dsp", O_WRONLY);
  39. ioctl(soundfd, SNDCTL_DSP_SPEED,&rate);
  40. ioctl(soundfd, SNDCTL_DSP_SETFMT, &format);
  41. ioctl(soundfd, SNDCTL_DSP_CHANNELS, &channels);
  42. #else
  43. if((soundfd = open("test.bin" , O_WRONLY | O_CREAT)) < 0)
  44. {
  45. fprintf(stderr , "can't open sound device!\n");
  46. exit(-1);
  47. }
  48. #endif
  49. }

  50. /*
  51. * This is perhaps the simplest example use of the MAD high-level API.
  52. * Standard input is mapped into memory via mmap(), then the high-level API
  53. * is invoked with three callbacks: input, output, and error. The output
  54. * callback converts MAD's high-resolution PCM samples to 16 bits, then
  55. * writes them to standard output in little-endian, stereo-interleaved
  56. * format.
  57. */

  58. static int decode(mp3_file *mp3fp);

  59. int main(int argc, char *argv[])
  60. {
  61. long flen, fsta, fend;
  62. int dlen;
  63. mp3_file *mp3fp;

  64. if (argc != 2)
  65. return 1;

  66. mp3fp = (mp3_file *)malloc(sizeof(mp3_file));
  67. if((mp3fp->fp = fopen(argv[1], "r")) == NULL)
  68. {
  69. printf("can't open source file.\n");
  70. return 2;
  71. }
  72. fsta = ftell(mp3fp->fp);
  73. fseek(mp3fp->fp, 0, SEEK_END);
  74. fend = ftell(mp3fp->fp);
  75. flen = fend - fsta;
  76. if(flen > 0)
  77. fseek(mp3fp->fp, 0, SEEK_SET);
  78. fread(mp3fp->fbuf, 1, BUFSIZE, mp3fp->fp);
  79. mp3fp->fbsize = BUFSIZE;
  80. mp3fp->fpos = BUFSIZE;
  81. mp3fp->flen = flen;

  82. set_dsp();

  83. decode(mp3fp);

  84. close(soundfd);
  85. fclose(mp3fp->fp);

  86. return 0;
  87. }

  88. static enum mad_flow input(void *data, struct mad_stream *stream)
  89. {
  90. mp3_file *mp3fp;
  91. int ret_code;
  92. int unproc_data_size; /*the unprocessed data's size*/
  93. int copy_size;

  94. mp3fp = (mp3_file *)data;
  95. if(mp3fp->fpos < mp3fp->flen) {
  96.         unproc_data_size = stream->bufend - stream->next_frame;
  97.         //printf("%d, %d, %d\n", unproc_data_size, mp3fp->fpos, mp3fp->fbsize);
  98.         memcpy(mp3fp->fbuf, mp3fp->fbuf + mp3fp->fbsize - unproc_data_size, unproc_data_size);
  99.         copy_size = BUFSIZE - unproc_data_size;
  100.         if(mp3fp->fpos + copy_size > mp3fp->flen) {
  101.             copy_size = mp3fp->flen - mp3fp->fpos;
  102.         }
  103.         fread(mp3fp->fbuf+unproc_data_size, 1, copy_size, mp3fp->fp);
  104.         mp3fp->fbsize = unproc_data_size + copy_size;
  105.         mp3fp->fpos += copy_size;

  106.         /*Hand off the buffer to the mp3 input stream*/
  107.         mad_stream_buffer(stream, mp3fp->fbuf, mp3fp->fbsize);
  108. ret_code = MAD_FLOW_CONTINUE;
  109. } else {
  110. ret_code = MAD_FLOW_STOP;
  111. }

  112. return ret_code;

  113. }

  114. /*
  115. * The following utility routine performs simple rounding, clipping, and
  116. * scaling of MAD's high-resolution samples down to 16 bits. It does not
  117. * perform any dithering or noise shaping, which would be recommended to
  118. * obtain any exceptional audio quality. It is therefore not recommended to
  119. * use this routine if high-quality output is desired.
  120. */

  121. static inline signed int scale(mad_fixed_t sample)
  122. {
  123. /* round */
  124. sample += (1L << (MAD_F_FRACBITS - 16));

  125. /* clip */
  126. if (sample >= MAD_F_ONE)
  127. sample = MAD_F_ONE - 1;
  128. else if (sample < -MAD_F_ONE)
  129. sample = -MAD_F_ONE;

  130. /* quantize */
  131. return sample >> (MAD_F_FRACBITS + 1 - 16);
  132. }

  133. /*
  134. * This is the output callback function. It is called after each frame of
  135. * MPEG audio data has been completely decoded. The purpose of this callback
  136. * is to output (or play) the decoded PCM audio.
  137. */

  138. //输出函数做相应的修改,目的是解决播放音乐时声音卡的问题。
  139. static enum mad_flow output(void *data, struct mad_header const *header,
  140. struct mad_pcm *pcm)
  141. {
  142. unsigned int nchannels, nsamples;
  143. mad_fixed_t const *left_ch, *right_ch;
  144. // pcm->samplerate contains the sampling frequency
  145. nchannels = pcm->channels;
  146. nsamples = pcm->length;
  147. left_ch = pcm->samples[0];
  148. right_ch = pcm->samples[1];
  149. short buf[nsamples *2];
  150. int i = 0;
  151. //printf(">>%d\n", nsamples);
  152. while (nsamples--) {
  153. signed int sample;
  154. // output sample(s) in 16-bit signed little-endian PCM
  155. sample = scale(*left_ch++);
  156. buf[i++] = sample & 0xFFFF;
  157. if (nchannels == 2) {
  158. sample = scale(*right_ch++);
  159. buf[i++] = sample & 0xFFFF;
  160. }
  161. }
  162. //fprintf(stderr, ".");
  163. write(soundfd, &buf[0], i * 2);
  164. return MAD_FLOW_CONTINUE;
  165. }

  166. /*
  167. * This is the error callback function. It is called whenever a decoding
  168. * error occurs. The error is indicated by stream->error; the list of
  169. * possible MAD_ERROR_* errors can be found in the mad.(or stream.h)
  170. * header file.
  171. */

  172. static enum mad_flow error(void *data,
  173. struct mad_stream *stream,
  174. struct mad_frame *frame)
  175. {
  176. mp3_file *mp3fp = data;

  177. fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
  178. stream->error, mad_stream_errorstr(stream),
  179. stream->this_frame - mp3fp->fbuf);

  180. /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */

  181. return MAD_FLOW_CONTINUE;
  182. }

  183. /*
  184. * This is the function called by main() above to perform all the decoding.
  185. * It instantiates a decoder object and configures it with the input,
  186. * output, and error callback functions above. A single call to
  187. * mad_decoder_run() continues until a callback function returns
  188. * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
  189. * signal an error).
  190. */

  191. static int decode(mp3_file *mp3fp)
  192. {
  193. struct mad_decoder decoder;
  194. int result;

  195. /* configure input, output, and error functions */
  196. mad_decoder_init(&decoder, mp3fp,
  197. input, 0 /* header */, 0 /* filter */, output,
  198. error, 0 /* message */);

  199. /* start decoding */
  200. result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

  201. /* release the decoder */
  202. mad_decoder_finish(&decoder);

  203. return result;
  204. }

说明:1、实例原本是基于音频OSS框架的,当然,在嵌入式领域,ALSA也是兼容OSS接口的;
        2、为了在ubuntu上调试方便,并没有直接往音频接口,而是创建了一个文件,直接往文件里面写;
        3、上述代码中的红色区域重点讲解一下

  1. static enum mad_flow input(void *data, struct mad_stream *stream)
  2. {
  3. mp3_file *mp3fp;
  4. int ret_code;
  5. int unproc_data_size; /*the unprocessed data's size*/
  6. int copy_size;

  7. mp3fp = (mp3_file *)data;
  8. if(mp3fp->fpos < mp3fp->flen) {
  9. unproc_data_size = stream->bufend - stream->next_frame;
  10. //printf("%d, %d, %d\n", unproc_data_size, mp3fp->fpos, mp3fp->fbsize);
  11. memcpy(mp3fp->fbuf, mp3fp->fbuf + mp3fp->fbsize - unproc_data_size, unproc_data_size);
  12. copy_size = BUFSIZE - unproc_data_size;
  13. if(mp3fp->fpos + copy_size > mp3fp->flen) {
  14. copy_size = mp3fp->flen - mp3fp->fpos;
  15. }
  16. fread(mp3fp->fbuf+unproc_data_size, 1, copy_size, mp3fp->fp);
  17. mp3fp->fbsize = unproc_data_size + copy_size;
  18. mp3fp->fpos += copy_size;

  19. /*Hand off the buffer to the mp3 input stream*/
  20. mad_stream_buffer(stream, mp3fp->fbuf, mp3fp->fbsize);
  21. ret_code = MAD_FLOW_CONTINUE;
  22. } else {
  23. ret_code = MAD_FLOW_STOP;
  24. }

  25. return ret_code;

  26. }

       我们设置的输入buff缓冲区的大小是8192字节,但是对于mp3文件来讲,不一定这8192个字节就刚好是若干个完整的帧,有可能会有若干字节是输入下一个帧的,所有要根据struct mad_stream中的两个指针,标示了缓冲区中的完整帧的起始地址:
  1. unsigned char const *this_frame;    /* start of current frame */
  2. unsigned char const *next_frame;    /* start of next frame */
那么
  1. unproc_data_size = stream->bufend - stream->next_frame;

得到剩余的下一个帧的数据,并且需要将其从buff数组的尾部拷贝到头部,再从mp3文件中读取一部分字节拼凑成下一个8192字节,提交给库去解码,如此周而复始。

       4、此代码解码出来的pcm可以加上44字节的wav头文件,则可以用播放器正常播放。

     五、如何从网络socket获取相应数据,边解码边播放

     由于我的项目是要实现一个远程播放器的功能,即手机端的mp3源文件通过wifi传输到开发板上解码播放,所以,对于输入缓冲区的控制就不像操作文件那个,可以通过file结构体精确控制好读取的数据位置了,为此,做了些许修改。

     可以开两个线程,一个线程用于接收socket数据,一个用于解码播放。主要是缓冲区的控制,可以如此实现:将接收buff[]大小设置为8192*10字节,然后,解码input函数里面的buff[]的大小设置为8192*11字节,也就是说,多余了8192用来缓冲多余的下一帧字节的数据(因为mp3文件的帧不会超过8192字节),那么,区别于上面的思路,我们可以固定的让socket的buff[]接收8192*10字节的数据,如果解码的buff[]里面初次解码后有剩余的数据,仍然将其复制到解码buff[]的头部,只是这时候还是将socket的buff[]的8192*10字节的数据加到解码buff[]的刚刚拷贝的数据后面,所以,这里调用mad_stream_buffer(stream, buf, bsize)中的bsize就是8192*10+剩余的帧数据大小了。

相关参考:

1、作者:cqulpj  网址: http://cqulpj.blogbus.com/logs/68406670.html

                               http://cqulpj.blogbus.com/logs/68406669.html

2、作者:李素科  网址: http://www.ibm.com/developerworks/cn/linux/l-cn-libmadmp3player/index.html

3、作者:liky125 网址: http://blog.chinaunix.net/uid-26073752-id-2392553.html

posted on 2012-07-15 11:19 小小程序员001 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/musicfans/archive/2012/07/15/2819301.html

相关文章:

oracle数据库增加新字段

--Add/modify columns alter table 表名 add 字段名 类型; --------------------------------------------------------------------- --Add comments to the columns comment on column CE00.eec000 is xxx;转载于:https://www.cnblogs.com/yby120/p/9138801.html

list @size 验证_第33期:上海自来水来自海上,回文字符串验证!

我准备了 1000 本电子书和计算机各领域高清思维导图 100 张&#xff0c;关注后回复【资源】&#xff0c;即可获取&#xff01;更可回复【内推】加入 BAT 内推群&#xff01;01、题目示例见微知著&#xff0c;发现一组数据很有趣&#xff0c;分享给大家。leetcode 第一题通过次数…

安装apache的时候80端口被PID为4的系统进程所占用

由于工作中需要直接从MySQL后台读取数据&#xff0c;所以安装了PHPnow&#xff0c;装的过程中提示Apache安装失败&#xff0c;80端口被占用。 在cmd中输入netstat –ano命令&#xff0c;发现80端口被一个PID为4的服务所占用&#xff0c;打开任务管理器&#xff0c;发现PID为4的…

PHP根据时间戳返回星期几

为什么80%的码农都做不了架构师&#xff1f;>>> <?php /*** 根据时间戳返回星期几* param string $time 时间戳* return 星期几*/ function weekday($time) {if(is_numeric($time)){$weekday array(星期日,星期一,星期二,星期三,星期四,星期五,星期六);return…

FastCGI与php-fpm

FastCGI&#xff1a;为了兼顾IIS下PHP的效率和安全&#xff0c;微软给出了FastCGI的解决方案。同ISAPI原理有些类似&#xff0c;就是减少CGI初始化等前置操作的消耗。FastCGI可以让PHP的进程重复利用而不是每一个新的请求就重开一个进程。同时FastCGI也可以允许几个进程同时执行…

postmaster.c 中的 ListenAddresses

在 postmaster.c 中看到这种代码&#xff0c;从Java程序员的角度&#xff0c;看起来是很不爽的: char *ListenAddresses; ...if (ListenAddresses){ char *rawstring; List *elemlist; ListCell *l; ... 到底何…

PHPCMS V9 杂记一

PHPCMS V9加载顺序 PHPCMS V9和V8相比&#xff0c;总体思路方向是一样&#xff0c;不同的是V9把OOP和MVC结合得更加完美。 打开根目录下面的index.php 三行代码&#xff0c;相比V8的 index.php来说 更加清楚&#xff0c; phpcms下面的base.php文件&#xff0c;是一个基础类&…

esp32 camera_利用Phyphox和ESP32蓝牙制作欧姆表测电阻

近日&#xff0c;微主在利用Phyphox和ESP32蓝牙研究热敏电阻的阻值与温度的关系时&#xff0c;需要绘制热敏电阻阻值与时间的关系图像&#xff0c;通过用手捏住或者放开热敏电阻&#xff0c;观察电阻与时间关系图像的变化情况&#xff0c;进而了解温度对热敏电阻的影响。将热敏…

linux tomcat集群配置笔记

趁最后一天假期,配置linux环境下的apache集群,巩固下,免的以后用到又忘记,网上东拼息凑,环境弄好后,整到blog,以便以后用到。 参考来源&#xff1a;http://www.linuxidc.com/Linux/2011-03/32859.htm 我用的版本&#xff1a; httpd-2.2.21.tar.gz apache-tomcat-6.0.32.tar.gz …

spring -- 自定义注解

我们直接通过代码解释自定义注解的使用及各个含义 package com.sysware.cloud.dts.annotation;import java.lang.annotation.*;Retention(RetentionPolicy.RUNTIME) Target({ElementType.METHOD}) Inherited Documented public interface DtTransactional {/** Whether need to…

angular 字符串转换成数字_蓝盟IT外包,Python算法的一般技术和嵌入式库|python|字符串|key|算法|调用...

近年来&#xff0c;随着python着火&#xff0c;python也开始受到很多程序员的喜爱。 很多程序员已经开始使用python作为第一语言。最近在python上刷问题时&#xff0c;我想去找python的刷问题常用库api和刷问题技术。 和c的STL库文档一样&#xff0c;但很遗憾没有找到。 因此&a…

Mapping Persistence Classes 笔记2---ValueType的形式和映射

2010年5月17日 简介&#xff1a; 前面的笔记着重讲解了实体类以及其class-mapping options&#xff0c;本章笔记将关注值类型的形式以及其OR映射选项。 值类型一般可分为两类&#xff1a;JDK类型和用户自定义类型。本章首先从实体类的使用JDK类型的properties开始&#xff0c;讲…

安装wampserver及配置php,phpmyadmin遇到的问题及解决方法

wampserver 安装好以后&#xff0c;打开&#xff0c;发现appache无法启动&#xff0c;查了一下&#xff0c;发现是前安装过iis&#xff0c;iis使用80端口&#xff0c;打开httpd.conf&#xff0c;把里面所有的80都改成了81&#xff0c;然后appache就可以正常启动了。 再配置wamp…

as一种模拟输入效果

这个小程序展现的是一种模拟输入的效果&#xff0c;比如你在键盘上随便输入什么&#xff0c;在屏幕上就会依次的显示“这句话不是我输入的&#xff0c;呵呵”。比较有意思。 var s:Sprite new Sprite; var t:TextField new TextField(); var i:Number0; var myText:String&qu…

signature验证/salt验证/token验证的作用

1.salt验证: salt是随机生成的一串字符,salt验证的作用是将生成的salt与加密的密码密文拼接后再次加密存储 这样可以是存储在数据库中的密码更加安全 2.signature验证: I、将token, timestamp, nonce, encrypt的内容按照大小字母顺序排列 II、按顺序将列表中排序号的内容拼接成…

算法导论课后习题解析 第四章 上

4.1-1 返回只包含绝对值最小的元素的子数组。 4.1-2 Maximun-Subarray(A)max -infinityfor i 1 to A.lengthsum 0for j i to A.lengthsum sum A[i]if sum > maxmax sumlow ihigh jreturn (low, high, max)每次内循环都利用上次累加的结果&#xff0c;避免重复运算…

win10商店打不开_科技资讯:Win10系统电脑的应用商店老是打不开还闪退怎么办

最近关于Win10系统电脑的应用商店老是打不开还闪退怎么办在网上的热度是非常高的&#xff0c;很多网友们也都是非常关注Win10系统电脑的应用商店老是打不开还闪退怎么办这个事情&#xff0c;为此小编也是在网上进行了一番搜索查阅相关的信息&#xff0c;那么如果说有感兴趣的网…

[原]tornado源码分析系列(三)[网络层 IOLoop类]

引言&#xff1a;由于都是在工作当中抽出时间看源代码&#xff0c;所以更新速度比较慢&#xff0c;但是还是希望通过对好的源码的分析和探讨&#xff0c;大家相互学习&#xff0c;发现不好的地方共同讨论。 上次讲了IOLoop中的几个重要的方法&#xff0c;inistance() 和 add_ha…

参悟JavaScript

引子 编程世界里只存在两种基本元素&#xff0c;一个是数据&#xff0c;一个是代码。编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力。 数据天生就是文静的&#xff0c;总想保持自己固有的本色&#xff1b;而代码却天生活泼&#xff0c;总想改变这个世…

SQL数据库无法附加 系统表损坏修复 数据库中病毒解密恢复

SQL数据库无法附加 系统表损坏修复 数据库中病毒解密恢复 开发此工具是为了 让手工恢复数据库物理故障时 更加简单便捷直观, 本工具用于物理修复独立处理大部分问题以及与DBCC配合完成修复各种数据库错误.特别是针对大型数据库上百G 上TB数据库&#xff0c;节约大量时间精力。 …

ODP.NET调用存储需要使用事务

今天发生在用ODP.NET调整一个存储过程时发生了两个奇怪的错误。 ORA-08103: object no longer exists ora-01410: invalid rowid网上都说是索引块有错误什么的&#xff0c;我索引也重建&#xff0c;表也重建了&#xff0c;但还是不行。 奇怪的是我直接测试存储过程是有结果的。…

HDU-1698-Just a Hook

HDU-1698-Just a Hook http://acm.hdu.edu.cn/showproblem.php?pid1698 还是成段更新线段树 #include<stdio.h> #include<string.h> #include<stdlib.h> #define N 100005 struct cam {int x;int y;int sum;int val; }list[N*4]; void build(int k,int x,in…

sketchup 255个su常用插件)_SketchUp领域的知乎,有胆来问!

你知道知乎、豆瓣、果壳……但你可能不知道【问吧】这是一个 SketchUp 领域的知乎(点击文末“阅读原文”可直接进入【问吧】)你可以找到关于 SketchUp 的任何话题&#xff1a;SketchUp、Vray、建模、插件、曲面、SUAPP、组件、导入、材质、渲染、导出、贴图、材质、错误报告、L…

js简单的抽屉菜单

闲暇时间用Jquery写了一个js简单的抽屉菜单。。<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml" > <…

checkedListBox的使用

1.添加项checkedListBox1.Items.Add("蓝色"); checkedListBox1.Items.Add("红色"); checkedListBox1.Items.Add("黄色");2. 判断第i项是否选中,选中为true,否则为falseif&#xff08;checkedListBox1.GetItemChecked(i)&#xff09;{return t…

Windows Phone开发(39):漫谈关键帧动画上篇 转:http://blog.csdn.net/tcjiaan/article/details/7550506...

尽管前面介绍的几种动画会让觉得很好玩了&#xff0c;但是&#xff0c;不知道你是否发现&#xff0c;在前面说到的一系列XXXAnimation中&#xff0c;都有一个共同点&#xff0c;那就是仅仅针对两个值的目标值之间产生动画&#xff0c;如果使用By&#xff0c;将在原值和加上By后…

性能定位常用命令整理

统计每秒钟Nginx收到多少请求&#xff1a; cat access.log | grep 2019:20:19:50 | wc -l 解释&#xff1a;access.log为Nginx的日志&#xff0c;通过Nginx的配置文件nginx.conf查看日志文件名称和位置&#xff0c;2019:20:19:50 表示获取20点19分50秒接收的请求数&#xff0c;…

4块硬盘做raid几_HP-P4500存储RAID硬盘离线数据恢复案例

在这里北亚小编分享一篇关于HP-P4500存储RAID硬盘离线数据恢复案例&#xff0c;经客户描述&#xff1a;一台HP-P4500的存储系统&#xff0c;底层是12块1TB的硬盘组的RAID。其中每6个1TB的盘一组&#xff0c;第一组的前面一部分组了一个RAID01&#xff0c;是存放HP-P4500嵌入式系…

十个利用矩阵乘法解决的经典题目

出自matrix67.com 好像目前还没有这方面题目的总结。这几天连续看到四个问这类题目的人&#xff0c;今天在这里简单写一下。这里我们不介绍其它有关矩阵的知识&#xff0c;只介绍矩阵乘法和相关性质。 不要以为数学中的矩阵也是黑色屏幕上不断变化的绿色字符。在数学中&…

maven生命周期理解

你可以仅仅调用clean来清理工作目录&#xff0c;仅仅调用site来生成站点。当然你也可以直接运行 mvn clean install site 运行所有这三套生命周期。 知道了每套生命周期的大概用途和相互关系以后&#xff0c;来逐个详细看一下每套生命周期&#xff0c;Clean和Site相对比较简单&…