读mp3文件ID3V2信息,文字编码转换…

本文介绍了一个C语言程序,该程序用于从MP3文件中提取ID3 V2元数据,并将其转换为UTF-8编码,最终通过curl命令发布到微博。涉及的技术包括文件读取、内存映射、元数据解析及网络请求。
提取mp3文件ID3V2信息,通过curl命令发送请求,发布微博。ID3V2信息为UTF-16编码,需要在发送curl命令之前先转码成UTF-8

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>

typedef struct id3_v2_head
{
    char Header[3];    //必须为"ID3"否则认为标签不存在
    unsigned char Ver;    //版本号ID3V2.3就记录3
    unsigned char Revision;    //副版本号此版本记录为0
    unsigned char Flag;    //存放标志的字节,这个版本只定义了三位,稍后详细解说
    unsigned char Size[4];    //标签大小,包括标签头的10个字节和所有的标签帧的大小
}id3_v2_head_t;

typedef struct id3_v2_frame
{
    char FrameID[4];  //用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表
    unsigned char Size[4];   //帧内容的大小,不包括帧头,不得小于1
    unsigned char Flags[2];   //存放标志,只定义了6位,稍后详细解说
}id3_v2_frame_t;

int get_id3_v2_info(char *string);
int publish_weibo(const char* hdr, const int info_idx[3][2]);
int convert_UTF16toUTF8(const char *input, int *insize, char *output, int *outsize);

int main(int argc,char **argv)
{
    char *filename;
    if(argc!=2) {
        return -1;
    }
    filename = argv[1];
    get_id3_v2_info(filename);
    return 0;
}

int get_id3_v2_info(char *string)
{
    int info_idx[3][2] = {0};
    char *filename=NULL;
    int ret = 0;
    id3_v2_head_t * id3_v2_head=NULL;
    id3_v2_frame_t* id3_v2_frame=NULL;
    int fd;
    char *hdr = NULL;
    long int id3_v2_head_length=0;
    long int id3_v2_frame_length=0;
    long int total_read=0;
    struct stat sb;
    char *info = NULL;
    filename=string;
    fd = open(filename, O_RDONLY);
    if(fd==-1)
    {
        return -1;
    }
    fstat(fd,&sb);
    hdr=(char*)mmap(NULL,sb.st_size,PROT_READ,MAP_PRIVATE,fd,0);
    if(hdr== MAP_FAILED)
    {
        return 0;
        close(fd);
    }
    id3_v2_head=(id3_v2_head_t *)malloc(sizeof(id3_v2_head_t));
    if(id3_v2_head==NULL)
    {
        munmap(hdr,sb.st_size);
        close(fd);
        return -1;
    }
    memcpy(id3_v2_head,hdr,sizeof(id3_v2_head_t));
    if(strncmp(id3_v2_head->Header, "ID3", 3))
    {
        printf("have no id3 v2 info\n");
        munmap(hdr,sb.st_size);
        close(fd);
        return -1;
    }
    printf("have  id3 v2.%d.%d info\n",id3_v2_head->Ver,id3_v2_head->Revision);
    id3_v2_head_length = (id3_v2_head->Size[0]&0x7F)*0x200000+(id3_v2_head->Size[1]&0x7F)*0x400+(id3_v2_head->Size[2]&0x7F)*0x80+(id3_v2_head->Size[3]&0x7F);
    printf("head length:%ld\n",id3_v2_head_length);
    total_read += sizeof(id3_v2_head_t);
        id3_v2_frame = (id3_v2_frame_t *)malloc(sizeof(id3_v2_frame_t));
        if(id3_v2_frame == NULL) {
            close(fd);
            munmap(hdr,sb.st_size);
            return -1;
        }
    while(total_read < id3_v2_head_length)
    {
        memset(id3_v2_frame, 0, sizeof(id3_v2_frame_t));
        memcpy((char*)id3_v2_frame, hdr+total_read, sizeof(id3_v2_frame_t));
        id3_v2_frame_length = id3_v2_frame->Size[0]*0x100000000+id3_v2_frame->Size[1]*0x10000+id3_v2_frame->Size[2]*0x100+id3_v2_frame->Size[3];
        if(id3_v2_frame_length == 0) {
            printf("id3_v2_frame_length == 0\n");
            break;
        }
        printf("size[0~3] = %d, %d, %d, %d, %d\n", id3_v2_frame->Size[0], id3_v2_frame->Size[1], id3_v2_frame->Size[2], id3_v2_frame->Size[3], id3_v2_frame_length);
        total_read+=sizeof(id3_v2_frame_t);
        info=(char*)malloc(id3_v2_frame_length);
        if(info==NULL) {
            printf("Failed to malloc.\n");
            break;
        }
        memset(info, 0, id3_v2_frame_length);
        memcpy(info, hdr+total_read+1, id3_v2_frame_length-1);
        if (strcmp(id3_v2_frame->FrameID, "TPE1") == 0) {
            info_idx[0][0] = total_read+1;
            info_idx[0][1] = id3_v2_frame_length-1;
        } else if (strcmp(id3_v2_frame->FrameID, "TIT2") == 0) {
            info_idx[1][0] = total_read+1;
            info_idx[1][1] = id3_v2_frame_length-1;
        } else if (strcmp(id3_v2_frame->FrameID, "TALB") == 0) {
            info_idx[2][0] = total_read+1;
            info_idx[2][1] = id3_v2_frame_length-1;
        }
        printf("%s:%s\n",id3_v2_frame->FrameID,info);
        total_read += id3_v2_frame_length;
        id3_v2_frame_length=0;
        free(info);
    }
    ret = publish_weibo(hdr, info_idx);
   
    munmap(hdr,sb.st_size);
    close(fd);
    free(id3_v2_frame);
    free(id3_v2_head);
    return ret;
}

int publish_weibo(const char* hdr, const int info_idx[3][2])
{
    #if 1
    // convert UTF16 to UTF8
    int insize = 0;
    int outsize = 0;
    // publish weibo
    char *info = NULL;
    int ret = 0;
    //const char* s0 = "curl -k --header "Accept-Charset: utf-8" -F access_token=2.00hone4D0ODM9ccc404334c137PJFB -F status="我正在听 ";
    const char* s0 = "curl -k -F access_token=2.00hone4D0ODM9ccc404334c137PJFB -F status="我正在听 ";
    const char* s2 = "" -F visible!=0 -F pic=@/home/zhangchunyan/tmp/test.jpg https://upload.api.weibo.com/2/statuses/upload.json";
    int offset = 0;
    int length = info_idx[0][1] + info_idx[1][1] + info_idx[2][1];
    if (length == 0) {
        printf("info_idx[0][1] + info_idx[1][1] + info_idx[2][1] == 0\n");
        return -1;
    }
    length += strlen(s0)+strlen(s2)+128;
    info=(char*)malloc(length);
    if(info==NULL) {
        printf("Failed to malloc.\n");
        return -1;
    }
    memset(info, 0, length);
    memcpy(info, s0, strlen(s0));
    offset += strlen(s0);
    insize = info_idx[0][1];
    outsize = info_idx[0][1]*2;
    printf("outsize=%d\n", outsize);
    convert_UTF16toUTF8(hdr+info_idx[0][0], &insize, info+offset, &outsize);
    printf("1:%s outsize=%d\n", info+offset, outsize);
    //for(int i = 0; i < info_idx[0][1] - outsize+10; i++) {
        //printf("%x ", *(info+offset+i));
        //if (i == 10) printf("\n");
    //} printf("\n");
    offset += outsize;
    offset += sprintf(info+offset, "《");
    insize = info_idx[1][1];
    outsize = info_idx[1][1]*2;
    printf("outsize=%d\n", outsize);
    convert_UTF16toUTF8(hdr+info_idx[1][0], &insize, info+offset, &outsize);
    printf("2:%s outsize=%d\n", info+offset, outsize);
    //for(int i = 0; i < info_idx[1][1] - outsize+10; i++) {
        //printf("%x ", *(info+offset+i));
        //if (i == 10) printf("\n");
    //} printf("\n");
    offset += outsize;
    offset += sprintf(info+offset, "》(分享自PIA)");
    memcpy(info+offset, s2, strlen(s2));
    printf("3:%s\n", info);
    ret = system(info);
    free(info);
    #endif
    return ret;
}

 
int convert_UTF16toUTF8(const char *input, int *insize, char *output, int *outsize)
{
    char* outstart = output;
    const char* processed = input;
    char* outend = output + *outsize;
    unsigned short* in = (unsigned short*) input;
    unsigned short* inend;
    unsigned int c, d, inlen;
    char *tmp;
    int bits;
 
    int isLittleEndian = 1;
 
    if((*insize % 2) == 1) (*insize)--;
    inlen = *insize / 2;
    inend = in + inlen;
    while((in < inend) && (output - outstart + 5 < *outsize))
    {
        if(isLittleEndian)
        {
            c= *in++;
        }
        else
        {
            tmp = (char *) in;
            c = *tmp++;
            c = c | (((unsigned int)*tmp) << 8);
            in++;
        }
        if((c & 0xFC00) == 0xD800)
        {
            if(in >= inend) break;
            if(isLittleEndian) {d = *in++;}
            else
            {
                tmp = (char *) in;
                d = *tmp++;
                d = d | (((unsigned int)*tmp) << 8);
                in++;
            }
            if((d & 0xFC00) == 0xDC00)
            {
                c &= 0x03FF;
                c <<= 10;
                c |= d & 0x03FF;
                c += 0x10000;
            }
            else
            {
                *outsize = output - outstart;
                *insize = processed - input;
                return -1;
            }
        }
 
        if(output >= outend) break;
        if (c < 0x80) {*output++ = c; bits= -6;}
        else if(c < 0x800) {*output++ = ((c >> 6) & 0x1F) | 0xC0; bits= 0;}
        else if(c < 0x10000) {*output++ = ((c >> 12) & 0x0F) | 0xE0; bits= 6;}
        else {*output++ = ((c >> 18) & 0x07) | 0xF0; bits= 12;}
 
        for(; bits >= 0; bits-= 6)
        {
            if (output >= outend)
            break;
            *output++ = ((c >> bits) & 0x3F) | 0x80;
        }
        processed = (const char*) in;
    }
 
    *outsize = output - outstart;
    *insize = processed - input;
 
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值