PDA

View Full Version : آموزش: ارسال و دریافت ویدئو در شبکه (چت تصویری)



silsin
دوشنبه 16 شهریور 1394, 12:16 عصر
با سلام

خوشبختانه در دنیای شبکه هر کاری که مربوط به ارتباط باشد رو می توان انجام داد .به بیان ساده این ارتباط هر چه می خواهد باشد و به هرچیزی که می خواهد منجر شود . چه ارتباط صوتی - تلفنی و یا ارسال و دریافت داده . مهمترین نکته که شرکت ها و متخصصان فعال در این زمینه همیشه به دنبال آن بوده و هستند پایین اوردن نرخ هزینه داده و به تبع افزایش سرعت ارتباط می باشد
نرخ هزینه داده : اشاره به مقدار داده دریافتی و یا ارسالی ***
در ادامه تاپیک های اموزشی خودم در زمینه برنامه نویسی شبکه اینبار می خواهیم روند ارتباط تصویری را برررسی کنیم . همانطور که در مقدمه بالا گفتم مهمترین نکته در این گونه ارتباط ها موضوع هزینه ارسال و دریافت داده است به طوری که مقدار داده های ارسالی و یا دریافتی کمتر باشد ما ارتباط بهتر و راحت تری خواهیم داشت اما نکته اینجاست هنوز که هنوزه ما روش کاملا بی نقص و ایده الی برای این کار نداریم . البته دیده ایم که شرکت های پیشرو و معروف در این زمینه مانند Skype راه کارهای بسیار خوب برای اینگونه ارتباط های تصویری را ارائه داده اند اما متاسفانه حداقل برای ما ایرانی ها استفاده از این راهکار ها بدون مشکل نبوده یعنی به خاطر کیفیت بد اینترنت کشور همه ما حداقل تجربه کیفیت نامناسب برای این گونه ارتباط ها را داشته ایم . همانطور که گفتم مهمترین نکته در این گونه ارتباط ها مبحث سرعت در انتقال می باشد . هرچه سرعت انتقال بیشتر باشد کیفیت هم بهتر خواهد بود و این خود مستلزم این است که داده های ارسالی و دریافتی تغییراتی داشته باشند . به طور معمول یک داده تصویری را می توان به مجموعه بسیار زیادی از تصاویر پشت سر هم تعبیر کرد که تعداد زیادی از انها یک فریم از ویدئو ما را تشکیل خواهند داد . نکته مهم در اینجا این است که هرچه کیفیت این فریم ها بیشتر باشد مسلما حجم داده به دست اماده نیز بیشتر خواهد شد . اگر چه بسیار از شرکت ها برای کنترل این بخش از ابزارهایی به نام Codec استفاده می کنند.
این Codec ها وظیفه تغییرات در بیت های دریافتی بر عهده دارند که به طبع به وسیله هر کدام از انها می توان نتیجه بهتر - فشرده تر را در اختیار گرفت . اگر چه نباید منکر این قضیه شد که استفاده از Codec ها خود کیفیت داده ها را دچار تغییر می کند اما مهمتر از کیفیت داده ها سرعت انتقال می باشد . اگر علاوه بر سرعت نیز باید کیفیت مناسب و قابل قبول تری را برای کاربر نهایی ارائه کرد.
در این تاپیک به وسیله ارائه نکات کلیدی می خواهیم روند ارسال و دریافت صوت در شبکه را بررسی کنیم .

کتابخانه هایی که از آنها برای این کار استفاده خواهیم کرد دو کتاب خانه :
DirectShow , Directx.Capture برای انجام Capture ویدئو از وب کم خواهد بود
این دو کتاب خانه را می توانید از پیوست زیر دریافت کنید
135061

در بخش اول این اموزش روند کپچر کردن ویدئو و در بخش دوم روند ارسال و دریافت تحت شبکه را بررسی می کنیم

1 - پروژه جدیدی ایجاد کرده فایل های کتابخانه را به آن اضافه کنید
2 - در بخش اعلان نیز این دو کتابخانه را اضافه کنید

using DirectX.Capture;
using DShowNET;


دو متغییر جدید تعریف خواهیم کرد :

public Capture capture = null;
public Filters filters = new Filters();



در بخش اعلان این دو متغییر جدید :

capture = new Capture(filters.VideoInputDevices[0], null);




filters.VideoInputDevices وظیفه برگرداندن دستگاه های موجود برای دریافت ویدئو را بر عهده دارد (با انتخاب index 0 ما اعلان خواهیم کرد که اولین device که همان دوربین پیش فرض سیستم عامل هست را انتخاب کن )
گزینه دوم نیز برای تعریف دستگاه دریافت صدا می باشد . در این مثال ما ان را null در نظر می گیریم چون می خواهیم فقط تصاویر را دریافت کنیم


capture.FrameRate = 15;
capture.FrameSize = new Size(320, 240);


به وسیله این دو property نیز به ترتیب فریم ریت و رزولوشن تصاویر را تعریف می کنیم


foreach (Filter ex in filters.VideoCompressors)
{
if (ex.Name == "Xvid MPEG-4 Codec")
{
capture.VideoCompressor = (ex);


}
}

به وسیله این شرط Codec مورد نظرمان را تعریف می کنیم (توضیحات مربوط به کدک و دلیل استفاده در بخش دوم بررسی خواهد شد )

برای متوقف کردن ضبط ویدئو از دستور زیر استفاده می کنیم

capture.Stop();



برای شروع ضبط از دستورات زیر استفاده می کنیم


capture.Cue();
Thread.Sleep(3000);
capture.Start();



عبارت Cue در خط اول برای اماده سازی فرایند ضبط و Start نیز برای شروع ضبط ویدئو می باشد
نکته : شما می توانید از Start به تنهایی استفاده کنید اما استفاده از Cue قبل از ان باعث میشود تا روند Start سریعتر شود



نکته : برای نمایش ویدئو شما باید از یک Picture Box در کنار یک Panel استفاده کنید


try
{
if (capture.PreviewWindow != p)
{
capture.PreviewWindow = p;
}
capture.FrameEvent2 += new Capture.HeFrame(CaptureDone);
capture.GrapImg();
isSending = true;
}
catch (Exception s)
{
MessageBox.Show(s.Message);
}


شروع نمایش و دریافت تصاویر با دستورات بالا امکان پذیر خواهد بود

دستور Grapimg برای دریافت تصاویر
event تعریف شده نیز برای عملیات در زمان کپچر تصاویر می باشد


private void CaptureDone(System.Drawing.Bitmap e)
{
try
{


picture.Image = e;


}
catch(Exception)
{

}



}



همانطور که مشاهده می کنید e به عنوان بافر دریافت شده به pictureBox ما نسبت داده شده است


پایان بخش اول

Imenam
سه شنبه 17 شهریور 1394, 21:25 عصر
خیلی خوب بود
لطفا بخش دوم رو هم شروع کنید

silsin
چهارشنبه 18 شهریور 1394, 12:10 عصر
بخش دوم :
در بخش قبلی نحوه دریافت ویدئو رو فرا گرفتیم در این بخش می خواهیم این مقدار را در شبکه تبادل کنیم
1 - کدکی که در بخش قبل از اون نام بردیم رو می تونید از ادرس زیر دانلود کنید
https://www.xvid.com/
2 -بخش سرور

Socket server_sock;
void server()
{
try
{
server_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server_sock.Bind(new IPEndPoint(IPAddress.Any, 6000));
server_sock.Listen(-1);

while (true)
{
try
{
Socket new_socket = server_sock.Accept();
NetworkStream ns = new NetworkStream(new_socket);
pictureBox_Remote.Image = Image.FromStream(ns);
ns.Close();
new_socket.Close();
}
catch (Exception)
{
}
}
}
catch(Exception){}

}






1 )
[/CSHARP]
server_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server_sock.Bind(new IPEndPoint(IPAddress.Any, 6000));
server_sock.Listen(-1);
[/CSHARP]
ابتدا یک سوکت جدید تعریف می کنیم این سوکت به پورت 6000 اتصال پیدا خواهد کرد


Socket new_socket = server_sock.Accept();
NetworkStream ns = new NetworkStream(new_socket);
pictureBox_Remote.Image = Image.FromStream(ns);
ns.Close();
new_socket.Close();


در شرط دائم التکرار ما نیز سوکت وظیفه دریافت کانکشن ها را بر عهده خواهد داشت .
نکته اصلی اینجاست که ما تصاویر یا داده ها را به صورت استریم و مستقیما از سوکت دریافت می کنیم و زمانی که دریافت کردیم به صورت هم زمان در pictureBox ما نمایش داده خواهد شد
نکته بعدی در مورد زمان و چگونگی اجرای این متد می باشد
برای اجرای این متد یک ترد جدید تعریف می کنیم
Thread ServerThread;

سپس در ابتدای اجرا برنامه یا فروم لود ان را start می کنیم

ServerThread = new Thread(new ThreadStart(server));
ServerThread.IsBackground = true;
ServerThread.Start();


پس از دریافت حال ارسال را بررسی می کنیم
برای دریافت :
در قسمت قبل grapimg را برای دریافت ویدئو تعریف کرده بودیم اینبار می خواهیم از همین ویژگی برای دریافت و ارسال استفاده کنیم
برای این کار متد جدیدی تعریف می کنیم وکدهای زیر را در ان وارد می نویسیم

try
{


if (capture != null)
{
if (capture.PreviewWindow != panelVideo)
{
capture.PreviewWindow = panelVideo;
}

capture.FrameEvent2 += new Capture.HeFrame(CaptureDone);
capture.GrapImg();


isSending = true;


}

}
catch (Exception) { }


متغییر isSending برای این تعریف شده که زمان ارسال را مشخص کنیم که پس از شروع دریافت تصاویر در فروم ما مجوز ارسال داده شود
در انتهای ایونت CaptureDone که تعریف کرده ایم

if (isSending)
ThreadPool.QueueUserWorkItem(new WaitCallback(SendVideoBuffer), buffer);

را برای ارسال بافر به سمت سرور تعریف می کنیم
رفرنس برای دستور استفاده شده :
https://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem%28v= vs.110%29.aspx

در متدی که وظیفه ارسال را دارد یعنی SendVideoBuffer

void SendVideoBuffer(object bufferIn)
{
try
{
TcpClient tcp = new TcpClient(PeerIP_TXT.Text, 6000);
NetworkStream ns = tcp.GetStream();
Image buffer = (Image)bufferIn;
buffer.Save(ns, System.Drawing.Imaging.ImageFormat.Tiff);

ns.Close();
tcp.Close();
}
catch (Exception) { }
}


bufferIn که به وسیله دستور وارد کرده در ایونت دریافت کرده بودیم را به وسیله دستور buffer.Save در NetworkStream مربوط به ارسال خود ذخیره می کنیم بدین صورت مقدار داده ما در ns ذخیره شده و به سمت مقصد ارسال می شود و به وسیله متد Server و روندی که توضیح داده شد دریافت می گردد

امیدوارم کاربردی بوده باشه
نمونه برنامه :
http://www.socketcoder.com/ArticleFile.aspx?ArticleID=72

نکات :
اگر کلی کد عجیب و غریب دیدن قاطی نکنین همین روندی که توضیح دادم رو توش پیدا کنین تا متوجه بشین چه جوری ساخته شده
برنامه ای که دانلود کردین از کدک های پیش فرض خود ویندوز استفاده می کنه ( یا حداقل هر کدکی که روی سیستمتون نصبه و کاری که من انجام دادم این بوده که کدک جدیدی که ازش اسم بردم رو به عنوان کدک پیش فرض تعریف کردم )
در نمونه برنامه ای که براتون گذاشتم روند به صورت p2p البته شما به وسیله استفاده از کدک های خوب مثل همینی که مثال زدم می تونید حجم کار رو پایین بیارین و ازش در سطح اینترنت استفاده کنید
و نکته اخر در مورد اینه که برنامه کلاینت و سرور در یک فرم تعریف شدن پس گیج نشین که چرا اینجوری شده
نکته بعدی هم در مورد دکمه های Start و Cue اگر به این دو دستور برخورد کردین این رو بدونین که این دو دستور برای شروع تصویر برداری و ذخیره بر روی حافظه سیستمیه یعنی فیلم برداری و تهیه فایل خروجی اما روشی که در اینجا استفاده شده داده ها رو بدون ذخیره کردن خواهد فرستاد

با تشکر

aria_68
یک شنبه 22 شهریور 1394, 00:13 صبح
نکته : برای نمایش ویدئو شما باید از یک Picture Box در کنار یک Panel استفاده کنید
[CSHARP]

try
{
if (capture.PreviewWindow != p)
{
capture.PreviewWindow = p;
}


ببخشید اینجا p رو چی در نظر گرفتید؟