您现在的位置:智能制造网>技术首页>技术交流

ARM + Qt + mplayer 开发过程

2013年11月07日 19:36来源:上海安嵌信息科技有限公司 >>进入该公司展台人气:1644

嵌入式技术:按照PC机的特点,根据特定的应用用需要,通过裁剪软硬件而组成的可以独立运行的系统的一门计算机技术。

流媒体的产生:随着 Niternet宽带化的发展趋势,高速的实时传输已成为实现,传统的多媒体在网络上客户端必须把多媒体档全部下载完毕后,在客户端才能播放,而流媒体以流的形式进行数字媒体的传送,在客户端可以边下载边观赏媒体节目。

项目结构 服务器(流媒体档)-------客户端机(播放流媒体档)

技术和实验平台:
Linux构建(实验平台的搭建),网络编程,应用软件的移植,Qt图形界面的开发。
ARM --- Mini2410
  PC机(windows 系统),linux虚拟平台,linux 系统RedHat 5,RedHat9
项目流程: 需求分析----概要设计------详细设计-----编程-----测试项目----修改完善

过程:
实验平台的搭建,bootloader的烧写,内核的烧写到flash,网络档系统的制作。
mplayer的移植,在linux x86上交叉编译mplayer,使得mplayer.能在ARM上运行。
服务器的搭建:搭建windows或linux 流媒体服务器,rtsp协议传输流媒体。
Qt图形界面的设计实现流媒体在客户端图形界面化操作和观赏。
Qt的移植。把在linux或window环境下开发出的QT应用程序移植的相应的嵌入式平台上。
实现嵌入式平台的流媒体播放,优化并改善传输性能和质量。

 

项目开始篇
流媒体Mplayer的移植
关键词:支持流媒体,能在ARM 平台上运行

开发环境:redhat 5
内核:2.6.18
Gcc -v 4.1.2

源码包的准备:
MPlayer-1.0rc1.tar.bz2 #MPlayer source code
arm-linux-gcc 3.3.2 #交叉编译器
live555-latest.tar.gz #live库的支持,流媒体功能必要
libmad-0.15.1b.tar.gz #解码库
由于MPlayer中默认的mp3*是mp3lib,使用的是浮点数运算,相当占用CPU资源,故在编译的时候可以使用 libmad进行音频输出,使用之前需要自己手动编译libmad,保证交叉编译器能够找到libmad库以及头文件,编译时增加--enable- mad就可以了。利用mad解码mp3文件,可以看到CPU占用率降低到了20%左右

安装好解码库到/usr/local/arm /3.3.2/lib
Tar xzvf libmad-0.15.1.tar.gz 解开解码包
Cd libmad-0.15.1
./configure --enable-fpm=arm --host=arm-linux --disable-shared --disable-debugging --prefix=/usr/local/arm/3.3.2/lib
Make
Make install
这样就可以看到在 /usr/local/arm/3.3.2/lib目录下多了include和lib目录,

安装live库到 /usr/local/lib/live
把Liv包拷贝到 /usr/local/lib/live
Tar zxvf live555-latest.tar.gz
Cd live
vim config.armlinux
修改如下:
CROSS_COMPILE= arm-linux-
LINK = $(CROSS_COMPILE)g++ -o
LIBRARY_LINK = $(CROSS_COMPILE)ld–o
LIBRARY_LINK_OPTS = $(LINK_OPTS)–r–Bstatic
保存后退出
./genMakefiles armlinux
Make

解码包libmad和流媒体支持包liv都安装好以后就可以交叉编译MPlayer 了

交叉编译MPlayer  
确保 export PATH=/usr/local/arm/3.3.2/bin:$PATH 也就是说
Arm-linux-gcc 的版本号是:3.3.2,并且此交叉编译器的安装路径是在/usr/local/arm/3.3.2/bin下,因为配置用到--cc=arm- linux-gcc
./configure --cc=arm-linux-gcc --host-cc=gcc --enable-cross-compile --target=arm-armv4l-linux --enable-linux-devfs --disable-win32 --disable-dvdread --enable-fbdev --disable-mencoder --enable-libavcodec --disable-liba52 --disable-mp3lib --enable-static --enable-live --disable-armv5te --disable-iconv --charset=noconv --enable-mad --enable-ossaudio --with-livelibdir=/usr/local/lib/live--with-extraincdir=/usr/local/arm/3.3.2/arm-linux/sys-include/:/usr/local/arm/3.3.2/lib/include --with-extralibdir=/usr/local/arm/3.3.2/arm-linux/lib:/usr/local/arm/3.3.2/lib/lib

make
到这里MPlayer可以说是已经移植成功了。

搭建服务器
我们用的是darwin服务器
准备安装服务器资源包
DarwinStreamingSrvr5.5.5-Windows 包
ActivePerl-5.10.1.1007-MSWin32-x86-291969 安装包
QuickTimeInstaller  
解压DarwinStreamingSrvr5.5.5-Windows 会自动解压的C盘DarwinStreamingSrvr目录
安装ActivePerl-5.10.1.1007-MSWin32-x86-291969
进入DarwinStreamingSrvr目录,双击 Install,输入用户名和密码
打开一个IE浏览器,输入地址:http://127.0.0.1:1220/,输入相应的用户名和地址。,设置好媒体文件存放目录,默认在 C:\Program Files\Darwin Streaming Server\Movies目录下面
用 QuickTime来测试服务器
rtsp://127.0.0.1:554/sample_100kbit.mp4
同样也可以在 linux下面:
./mpalyer rtsp://127.0.0.1:554/sample_100kbit.mp4

----------------------------------------------------------
支持流媒体的视频文件mp4 ,可以用MP4Box处理普通mp4文件,使之支持流媒体。处理方法是:
解压MP4Box,并把它放入相应的文件夹,同时把MP4视频文件也放进来,在dos 下进行如下命令
MP4Box fileName -hint
这样这个文件就可以支持流媒体播放了。
----------------------------------------------------------
到现在为止,我们已经完成了实验环境的搭建,mplayer的移植,
以及Windows DarwinServer服务器的搭建,现在我们已经可以在ARM板上通过流媒体的方式播放windows DarwinServer里的视频了,流媒体的功能基本上实现,但是做为一个完整的应用软件,肯定要有操作界面。接下来 具体来介绍一下在QT中调用MPlayer。

应该来说,用QT专门编写操作界面是一件比较简单的事情。但是如果要在QT调用MPlayer,实现大部分功能却是一件并不容易的事情。接下来我详细的说明一下MPlayer的实现:

根据播放流媒体文件的特点
./mpalyer rtsp://127.0.0.1:554/sample_100kbit.mp4
我们必须在QT上获取服务器端的文件名。
难点一:获取服务器端媒体文件目录里的文件名。
难点二:如何在QT中调用MPlay
-----------------------------
我获取服务器端文件列表的方法实现如下,我认为这样还是一种比较好的方法:

------------------------------------------------------------------------------------------------------------

 

QT调用MPlayer应用程序的编写

在编写之前由于没有编写过调用外部应用程序的QT程序,所以一开始就觉得可能比较难,但是当我把相关的资料下载过来,凭借自己对QT的熟悉应用,一路走过来都十分的顺利,万事开头难!
在QT的编写过程中用到一个非常重要的类:
Qproces 创建一个进程
--------------------------播放功能的实现代码 -----------------------------------
  process->write("quit\n");
  process = new QProcess(this);
connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
process->setProcessChannelMode(QProcess::MergedChannels);
  // fname = ui->listWidget->selectedItems()[0]->text();
  Info.id = 1;
  Info.fName = ui->listWidget->selectedItems()[0]->text();
  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());
-----------------------------------------------------------------------------------------

播放部分详解:
process->write("quit\n"); 先关闭原来的进程
process = new QProcess(this); 创建一个新的进程
connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots())); 信号与曹链接,有新进程创建就会触发
readyReadStandardOutput()信号,获取新播放文件的信息。
Info.fName = ui->listWidget->selectedItems()[0]->text(); 获取文件名
QStringList args;
args<<"-slave";
args<<"-quiet";
args<<"-wid"<<QString::number(ui->frame->winId());
args<<Info.fName;
// 以上为linux播放必须参数
播放函数:
process->start(mplayerPath+"/mplayer",args);
参数一:应用软件mplayer的存放路径,我把它存放在项目文件夹里
参数二:为播放媒体文件的参数
------------------------------------------------------------------------------------


----------------------------- 以下是我的Widget.cpp的实现部分--------------
#Include "widget.h"
#Include "ui_widget.h"
#Include <QPainter>
#Include <QPalette>
#Include <dirent.h>
#Include <QFileDialog>
#Include <QStringList>
#Include <QListWidgetItem>
#Include "titlebar.h"

Widget::Widget(QWidget *parent) :
  QWidget(parent),
  ui(new Ui::Widget)
{
  ui->setupUi(this);
  ui->gridLayout->setMargin(0);
  ui->gridLayout->setSpacing(0);
  this->setWindowTitle(tr("My Mplayer"));

  ui->frame_2->setAutoFillBackground(true);
  QPalette palette;
  palette.setBrush(ui->frame_2->backgroundRole(),QBrush(QPixmap(":/down")));
  ui->frame_2->setPalette(palette);

  ui->frame->setMinimumWidth(this->width()-ui->tabWidget->width());
  ui->videoSlider->setMinimumWidth(this->width());
  ui->tabWidget->hide();
  ui->soundSlider->hide();

  ui->quit->setToolTip(tr("停止"));
  ui->prebtn->setToolTip(tr("上一集"));
  ui->next->setToolTip(tr("下一集"));
  ui->play_stop->setToolTip(tr("播放/暂停"));
  ui->list->setToolTip(tr("打开播放列表"));

  // ui->listWidget->setStyleSheet("color:red");
  connect(ui->listWidget,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(getlist()));
  connect(ui->listWidget_2,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(getlofileList()));
  process = new QProcess(this);
  char buff[40];
  mplayerPath = getcwd(buff,40);

  i = 0;
  s = 0;

  isPlay = true;
isStop = false;
connect(ui->videoSlider,SIGNAL(sliderMoved(int)),this,SLOT(seek_video(int)));
  connect(ui->soundSlider,SIGNAL(valueChanged(int)),this,SLOT(seek_volum(int)));

  ui->videoSlider->setRange(0,100);
  ui->soundSlider->setRange(0,10);
  ui->soundSlider->setValue(5);

  timer = new QTimer(this);

  connect(timer,SIGNAL(timeout()),this,SLOT(get_time_slots()));
  timer->start(1000);

  ui->label->setStyleSheet("color:rgb(182, 182, 182)");
  ui->label3->setStyleSheet("color:rgb(182, 182, 182)");
  ui->label->setText("00:00:00");
  ui->label3->setText("00:00:00");
}

Widget::~Widget()
{
  delete ui;
}

void Widget::changeEvent(QEvent *e)
{
  QWidget::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
  ui->retranslateUi(this);
  break;
  default:
  break;
  }
}

void Widget::on_list_clicked()
{
  if(i == 0)
  {
  ui->tabWidget->show();

  }
  else if(i == 1)
  {
  ui->tabWidget->hide();
  }
  i++ ;
  if(i==2)
  i=0;
}



void Widget::on_sound_clicked()
{

  ui->soundSlider->show();
  if(s == 0)
  {
  ui->soundSlider->show();

  }
  else if(s == 1)
  {
  ui->soundSlider->hide();
  }
  s++ ;
  if(s==2)
  s=0;
}

//---------------------------------- 获取本地列表-----------------------------
void Widget::getlofileList()
{
  int lo = ui->listWidget_2->currentRow();
  if(lo == 0) //点击选择获取列表
  {
  QStringList lofn=QFileDialog::getOpenFileNames(
  this,
  tr("选择视频文件"),
  "/",
  "*.*");
  int tmp;
  for(tmp = 0;tmp<lofn.size();tmp++)
  {
  qDebug()<<lofn.at(tmp);
  QListWidgetItem *loItem = new QListWidgetItem(lofn.at(tmp));
  ui->listWidget_2->addItem(loItem);
  }
  }
  else
  {
  process->write("quit\n");
  process = new QProcess(this);
  connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
  process->setProcessChannelMode(QProcess::MergedChannels);

  Info.id=0;
  Info.fName = ui->listWidget_2->selectedItems()[0]->text();
  // fname = ui->listWidget_2->selectedItems()[0]->text();

  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());
  // if(0)
  // {
  // args<<fname;//本地播放
  args<<Info.fName;
  // }
  // qDebug()<<fname;

  // args<<LIVE+fname;//流媒体播放
  process->setProcessChannelMode(QProcess::MergedChannels);

  // Box.setTitletxt(tr("正在播放电影--")+Info.fName);
  // Box.set_titleBartxt(tr("正在播放电影--")+Info.fName);
  // this->setWindowTitle(tr("正在播放电影--")+fname);
  // label3->setText(tr("正在缓冲-----请稍等--"));
  // TitleBar::setTitletxt(tr("正在播放电影--")+fname);
  process->start(mplayerPath+"/mplayer",args);

  // timer2->start(7000);
  // connect(process,SIGNAL(readyReadStandardOutput()),play,SIGNAL(clicked()));

  // getbuffing();

  // QIcon ic;
  // ic.addPixmap(QPixmap(":/play_stop"));
  ui->play_stop->setStyleSheet("background-image:url(:/play_stop)");
  // ui->play_stop->setIcon(ic);
  // isPlay=true;

  }
}

//--------------------------------获取在线列表-------

  void Widget::getlist()
  {
  int ck = ui->listWidget->currentRow();

  if(ck == 0)
  {
  int listf;
  qDebug()<<count;
  for(listf=count;listf>0;listf--)
  {
  ui->listWidget->takeItem(listf);
  }
  getfileName();
  QString fn;
  int listf1;
  for(listf1=0;listf1<count;listf1++)
  {
  fn = cFile_name[listf1];
  QListWidgetItem *items = new QListWidgetItem(fn);
  ui->listWidget->addItem(items);
  }
  }
  else
  {
  process->write("quit\n");
  process = new QProcess(this);
  connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
  process->setProcessChannelMode(QProcess::MergedChannels);
  // fname = ui->listWidget->selectedItems()[0]->text();
  Info.id = 1;
  Info.fName = ui->listWidget->selectedItems()[0]->text();
  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());
  if(0)
  {
  args<<"/home/Movies/"+fname;//本地播放
  }
  // args<<LIVE+fname;//流媒体播放
  args<<LIVE+Info.fName;
  process->setProcessChannelMode(QProcess::MergedChannels);
  // this->setWindowTitle(tr("正在播放电影--")+fname);
  // label3->setText(tr("正在缓冲-----请稍等--"));
  // TitleBar::setTitletxt(tr("正在播放电影--")+fname);
  process->start(mplayerPath+"/mplayer",args);

  // timer2->start(7000);
  // connect(process,SIGNAL(readyReadStandardOutput()),play,SIGNAL(clicked()));
  // getbuffing();
  // QIcon ic;
  // ic.addPixmap(QPixmap(":/play_stop"));
  ui->play_stop->setStyleSheet("background-image:url(:/play_stop)");
  // ui->play_stop->setIcon(ic);
  // isPlay=true;

  }

}

void Widget::on_play_stop_clicked()
{
  if(!isPlay)//如果不是播放中
  {
  if(isStop)//如果所停止状态
  {
  if(Info.id == 0)//如果是在播放本地的电影
  {
  if(ui->listWidget_2->currentRow() == 0)
  {
  ui->listWidget_2->setCurrentRow(1);
  }
  Info.fName = ui->listWidget_2->currentItem()->text();
  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());
  args<<Info.fName;//流媒体播放
  process->setProcessChannelMode(QProcess::MergedChannels);
  // this->setWindowTitle(tr("正在播放电影--")+fname);
  process->start(mplayerPath+"/mplayer",args);

  }
  else if(Info.id == 1)//如果所在播放在线电影
  {
  if(ui->listWidget->currentRow()==0)//播放当前电影
  {ui->listWidget->setCurrentRow(1);}
  // fname = ui->listWidget->currentItem()->text();
  Info.fName = ui->listWidget->currentItem()->text();
  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());
  // args<<MOVIES+fname;
  if(0)
  {
  args<<MOVIES+fname;//本地播放
  }
  // args<<LIVE+fname;//流媒体播放

  args<<LIVE+Info.fName;
  process->setProcessChannelMode(QProcess::MergedChannels);
  // this->setWindowTitle(tr("正在播放电影--")+fname);
  process->start(mplayerPath+"/mplayer",args);
  }
  // label3->hide();
  // getbuffing();
  isStop=false;
  }
  else//如果是暂停状态
  {
  process->write("pause\n");

  }
  // QIcon ic;
  // ic.addPixmap(QPixmap(":/play_stop"));
  // ui->play_stop->setIcon(ic);
  ui->play_stop->setStyleSheet("background-image:url(:/play_stop)");
  isPlay = true;

  }
  else//如果所播放状态
  {
  // ui->play_stop->setIcon(QIcon(":/stop"));
  isPlay = false;
  ui->play_stop->setStyleSheet("background-image:url(:/stop)");
  process->write("pause\n");


  }
}

//------------------------------------ 上一首-----------------------------------------

void Widget::on_prebtn_clicked()
{
  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());

  if(Info.id == 0)//正在播放本地,就播放本地列表的上一首
  {
  if((ui->listWidget_2->currentRow()-1)>0)//如果在有效范围内
  {
  ui->listWidget_2->setCurrentRow(ui->listWidget_2->currentRow()-1);
  Info.fName = ui->listWidget_2->currentItem()->text();
  args<<Info.fName;

  process->setProcessChannelMode(QProcess::MergedChannels);
  // this->setWindowTitle(tr("正在播放电影--")+fname);
  process->write("quit\n");
  process = new QProcess(this);
  connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
  process->setProcessChannelMode(QProcess::MergedChannels);
  process->start(mplayerPath+"/mplayer",args);

  }
  }
  else if(Info.id == 1)//如果在播放在线列表 获取上一集
  {

  if((ui->listWidget->currentRow()-1)>0)
  {
  ui->listWidget->setCurrentRow(ui->listWidget->currentRow()-1);
  // fname = ui->listWidget->currentItem()->text();
  Info.fName = ui->listWidget->currentItem()->text();
  if(0)
  {
  args<<MOVIES+fname;//本地播放
  }
  args<<LIVE+Info.fName;//流媒体播放
  process->setProcessChannelMode(QProcess::MergedChannels);
  // this->setWindowTitle(tr("正在播放电影--")+fname);
  process->write("quit\n");
  process = new QProcess(this);
  connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
  process->setProcessChannelMode(QProcess::MergedChannels);
  process->start(mplayerPath+"/mplayer",args);

  }
  }
}

//-----------------------------------下一首 ---------------------------------------

void Widget::on_next_clicked()
{

  QStringList args;
  args<<"-slave";
  args<<"-quiet";
  args<<"-wid"<<QString::number(ui->frame->winId());

  if(Info.id == 0)//在播放本地的电影,播放下一首
  {
  qDebug()<<ui->listWidget_2->count()<<"看到了吗?";

  if(ui->listWidget_2->currentRow()+1 < ui->listWidget_2->count())
  {
  ui->listWidget_2->setCurrentRow(ui->listWidget_2->currentRow()+1);
  }
  Info.fName = ui->listWidget_2->currentItem()->text();
  args<<Info.fName;

  process->write("quit\n");
  process = new QProcess(this);
  connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
  process->setProcessChannelMode(QProcess::MergedChannels);
  process->start(mplayerPath+"/mplayer",args);


  }
  else if(Info.id == 1)//如果所在线播放
  {
  if((ui->listWidget->currentRow()+1)<=count)//:--?? 哈哈,第0位条目被占用了
  {
  ui->listWidget->setCurrentRow(ui->listWidget->currentRow()+1);
  Info.fName = ui->listWidget->currentItem()->text();

  // args<<MOVIES+fname;
  if(0)
  {
  args<<MOVIES+fname;//本地播放
  }
  args<<LIVE+Info.fName;//流媒体播放

  // this->setWindowTitle(tr("正在播放电影--")+fname);
  process->write("quit\n");
  process = new QProcess(this);
  connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));
  process->setProcessChannelMode(QProcess::MergedChannels);
  process->start(mplayerPath+"/mplayer",args);
  }
  }
}


void Widget::on_quit_clicked()
{
  if(!isStop)//如果原来不是停止的,按下就会停止,如果原来本来就所停止的,按下什么都不作
  {
  // play->setIcon(QIcon(":/stop"));
  ui->play_stop->setStyleSheet("background-image:url(:/stop)");
  process->write("quit\n");
  isStop = true;
  isPlay = false;
  }
}

void Widget::seek_video(int k)
{
  qDebug()<<k;
  if(process && process->state()==QProcess::Running)
  {
  process->write(QString("seek " + QString::number(k) + " 1\n"));
  }
}

void Widget::seek_volum(int sk)
{
  if(sk>5)
  {
  process->write(QString("volume "+QString::number(sk-5)+"\n").toAscii());
  }
  if(sk<5)
  {
  process->write(QString("volume "+QString::number(sk-5)+"\n").toAscii());
  }

}

void Widget::get_time_slots()
{
  if(isPlay)
  {
  process->write("get_time_pos\n");
  process->write("get_time_length\n");
  }
}

void Widget::back_message_slots()
{
  while(process->canReadLine())
  {
  QString message(process->readLine());
  // qDebug()<<message;
  QStringList message_list = message.split("=");
  // qDebug()<<"list[0]" << message_list[0];

  if(message_list[0]=="ANS_TIME_POSITION")
  {
  curr_time = message_list[1].toDouble();
  // qDebug()<<"curr_time="<<curr_time;
  QTime time = int_to_time(curr_time);
  ui->label->setText(time.toString("hh:mm:ss"));
  ui->videoSlider->setValue(100*curr_time/file_length);
  }
  else if(message_list[0] == "ANS_LENGTH")
  {
  file_length = message_list[1].toDouble();
  QTime time = int_to_time(file_length);
  ui->label3->setText(time.toString("hh:mm:ss"));
  }
  }

}

QTime Widget::int_to_time(int seconds)
{
  int sec = 0,min =0,hour = 0;
  QTime time;
  if(seconds < 60)
  {
  sec = seconds;
  min = 0;
  hour = 0;
  }
  if(seconds>=60 && seconds<3600)
  {
  sec = seconds%60;
  min = seconds/60;
  hour = 0;
  }
  if(seconds >=3600)
  {
  sec = seconds%60;
  min = (seconds /60)%60;
  hour = seconds /3600;
  }
  time.setHMS(hour,min,sec);
  return time;
}

全年征稿/资讯合作 联系邮箱:1271141964@qq.com
  • 凡本网注明"来源:智能制造网"的所有作品,版权均属于智能制造网,转载请必须注明智能制造网,https://www.gkzhan.com。违反者本网将追究相关法律责任。
  • 企业发布的公司新闻、技术文章、资料下载等内容,如涉及侵权、违规遭投诉的,一律由发布企业自行承担责任,本网有权删除内容并追溯责任。
  • 本网转载并注明自其它来源的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品来源,并自负版权等法律责任。
  • 如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。


编辑精选

更多


宣传样本推荐图书

旗下子站

工控网机器人仪器仪表物联网3D打印工业软件金属加工机械包装机械印刷机械农业机械食品加工设备制药设备仓储物流环保设备造纸机械工程机械纺织机械化工设备电子加工设备水泥设备海洋水利装备矿冶设备新能源设备服装机械印染机械制鞋机械玻璃机械陶瓷设备橡塑设备船舶设备电子元器件电气设备



关于我们|本站服务|会员服务|企业建站|旗下网站|友情链接| 兴旺通| 产品分类浏览|产品sitemap

智能制造网 - 工业4.0时代智能制造领域“互联网+”服务平台

Copyright gkzhan.comAll Rights Reserved法律顾问:浙江天册律师事务所 贾熙明律师

客服热线:0571-87756395加盟热线:0571-87759904媒体合作:0571-89719789

客服部:编辑部:展会合作:市场部:

关闭