Tuesday, August 16, 2011

Upload and Convert Video/Audio File to Flash Video (flv) and Progressive Streaming using ASP.NET handler

In my previous blog here I implemented a asp.net handler for uploading file using ajax upload and I am using this file upload for uploading video and audio files. FLV is best format for website use.

But your can upload video in any format (.mov, .avi, .wav, flv). But user can see video from site in flv format best for website. ASP.NET handler is used for pseudo-streaming and flowplayer is used to show flv files. So using this application you can upload video file and after uploading video file will be converted to flv format. User can also play the uploaded FLV formatted video file using flawplayer. You can also play MPEG-4 H.264 (.mp4) formatted file using flawplayer . I will discuss about progressive streaming of .mp4 also.

Uploading Video File And Convert to Flash Video (flv) Format

I am using the same valum’s upload control here for uploading video/ audio file. This support multiple upload by default but I need single file upload here. Also I have given restriction in allowed extensions.

var uploader = new qq.FileUploader({ 
element: document.getElementById('file-uploader-demo1'),
action: 'FileUpload.ashx',
template: '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
'<div class="qq-upload-button">Upload a video</div>' +
'<ul class="qq-upload-list"></ul>' +
'</div>',
multiple: false,
allowedExtensions: ['flv', 'mov', 'mp4', 'avi', 'mgp', 'wmv'],
debug: true,
onComplete: function (id, fileName, responseJSON) {
………….

});
}
});





Here you can see I have changed valum’s upload options for supporting single upload and only video files. I have also changed template of upload button. I will discuss OnComplete code later.



Now suppose that user upload flv file so I do not need to convert flv format as I am displaying flv file only. But if user upload other formatted file like .mov, avi, mpeg or .wav then I want to convert into my flv format to display video from my site. FFMPEG is a very lovely tool for converting video file. This tool not only convert video in other format but also we can extract audio from video and also can generate thumbnail from video file frame.



I am not familiar with ffmpeg command arguments so I used standard options for Flash Video (flv). The format I have got from WinFF is



"ffmpeg.exe" -i "sample.avi" -vcodec flv -f flv -r 29.97 -s 320x240 -aspect 4:3 -b 300k -g 160 -cmp dct  -subcmp dct  -mbd 2 -flags +aic+cbp+mv0+mv4 -trellis 1 -ac 1 -ar 22050 -ab 56k "sample.flv"



This converted my 25MB .wav file to 1.4M flv file. I want to run this command after uploading user avi file in server but how can I run .exe file using asp.net basic authentication account. So for running “ffmpeg.exe” I have impersonate to specific user account. Here http://support.microsoft.com/kb/306158 you can see how to impersonate a specific user in code. After converting video file into flv format I have undo impersonate from that account.



 



if (Path.GetExtension(phyicalFilePath).Equals(".flv")) return phyicalFilePath;
if (AuthenticationHelper.ImpersonateValidUser("user", ".", "********"))
{
var argument = string.Format("-i {0} -vcodec flv -f flv -r 29.97 -s 320x240 -aspect 4:3 -b 300k -g 160 -cmp dct -subcmp dct -mbd 2 -flags +aic+cbp+mv0+mv4 -trellis 1 -ac 1 -ar 22050 -ab 56k {1}", phyicalFilePath, Path.ChangeExtension(phyicalFilePath, "flv"));

ProcessStartInfo process = new ProcessStartInfo(ffmpegPhysicalPath, argument);
Process proc = new Process();
proc.StartInfo = process;
proc.Start();
proc.WaitForExit();
AuthenticationHelper.UndoImpersonation();
return Path.ChangeExtension(phyicalFilePath, "flv");
}

return string.Empty;




Here you can see command for converting video file into flash video (flv) format.  You need to set ffmpegPhysicalPath to the location of ffmpeg.exe file.



After converting video file into flv format path of flv file is sent to user. But I also want to show a thumbnail splash image so that user can understand that video is uploaded. And on clicking splash image ASP.NET handler will be called and user can see video using flawplayer.



Generating thumbnail image from video file is very easy using ffmpeg . In flawplayer forum you can see the details about generating thumbnail from video http://flowplayer.org/tutorials/generating-thumbs.html.



After completing these steps I have sent a JSON response to containing flv location and image location.



                        var flvpath =ConvertToFLV(phyicalFilePath);
var tumbnail = CreateThumbnail(phyicalFilePath);


context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" +
Path.GetFileName(flvpath) + "\", image:\"" + path+"/"+Path.GetFileName(tumbnail) + "\"}");



 



Uploading Large File



You might be failed to upload large as by default IIS  supported content length is 30000000  Byte.



image



You also need to set maxRequestLength in webconfig otherwise you will get exception while fetching large file. Suppose that I support maximum 2G size file in my site. My webconfig settings are :



<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="4124672" requestValidationMode="2.0" />
</system.web>

<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4223664128"></requestLimits>
</requestFiltering>
</security>
</system.webServer>




Here maxRequestLength is in KB and maxAllowedContentLength in Byte format. Now you can upload maximum 2G file using Valums upload control.



Watching Progressive Streaming Video using  ASP.NET Handler



Flowplayer forum http://flowplayer.org/forum/5/14702#post-14702 discussed well steps to implement progressive streaming using ASP.NET handler. I have copy paste and used same code in my handler. So when flowplayer request to server to get flv file then FLVStreaming handler will be called which provide flv file progressively.



You can download flowplayer swf file from FlowPlayer site. As tumbnail of video and flv locaiton is send after uploading using valums control. So code here OnComplete function is



 var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader-demo1'),
……


                onComplete: function (id, fileName, responseJSON) {
if (responseJSON.success)
$("#videoContainer").append("<div class='player' style='display:block;width:400px;height:400px;background-image:url(" + responseJSON.image + ");' href='" + responseJSON.path + "'><img src='images/play_large.png' alt='Play this video' /></div>");

flowplayer("div.player", "Scripts/flowplayer/flowplayer-3.2.7.swf", {
clip: {
autoPlay: false,
autoBuffering: true
}
});
}
});




Here thumbnail image is set as background and a play image displayed in middle. after clicking on the image flowplayer script will be called and request for flv file to server and then FLVStreaming handler will be called.



image



Streaming MP4 Video



FlowPlayer also support H.264 mp4 video format. You can also use JW Player.



Converting video file into mp4 formatted video file



ffmpeg command for converting video file into h264 mp4 formatted video file is



var argument = string.Format("-i {0} -crf 35.0 -vcodec libx264 -acodec libfaac -ar 48000 -ab 128k -coder 1 -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -me_method hex -subq 6 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -threads 0 {1}", phyicalFilePath, Path.ChangeExtension(phyicalFilePath, "mp4"));


The implementation of handler for mp4 can be found here http://www.mediasoftpro.com/articles/asp.net-progressive-mp4-streaming.html. You can see there client type is different for mp4. You can also use JW Player. But I do not want to mix here two implementation so I did not provide mp4 handler here.



 



Streaming MP3 Audio



Then handler for MP3 audio is same as flv player but just content- type is different.



context.Response.AppendHeader("Content-Type", "audio/mp3");
context.Response.AppendHeader("Content-Length", fs.Length.ToString());


Playing MP3 using flowplayer



Flowplayer is also support mp3 file. We can change configuration of FlowPlayer using the following script.



  var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader-demo2'),
action: 'AudioUpload.ashx',
multiple: false,
template: '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
'<div class="qq-upload-button">Upload a mp3</div>' +
'<ul style="display:none" class="qq-upload-list"></ul>' +
'</div>',
allowedExtensions: ['mp3'],
debug: true,
onComplete: function (id, fileName, responseJSON) {
if (responseJSON.success)

$("#audioContainer").append("<a id='audioPlayer' style='display:block;height:30px;' href='" + responseJSON.path + "'/>");
$f("audioPlayer", "Scripts/flowplayer/flowplayer-3.2.7.swf", {

// fullscreen button not needed here
plugins: {
controls: {
fullscreen: false,
height: 30,
autoHide: false
}
},

clip: {
autoPlay: false,

// optional: when playback starts close the first audio playback
onBeforeBegin: function () {
$f("player").close();
}
}

});
}
});


 



After upload is complete the flowplayer will be displayed like this. And clicking on play button it will call MP3Streaming handler and run mp3 in progressing manner.



image



Source Code



http://dl.dropbox.com/u/20275838/FileUploaderSol.rar

Friday, July 29, 2011

Silverlight Drawing Tool: Silver Draw Whiteboard with Undo , Redo and Save as JPEG

My requirement was to create a whiteboard where user can draw simple shapes  and also erase drawing. User can also undo and redo drawing as they do in MS paint. After completing drawing user can also save the drawing as Image.

I did not wanted to reinvent wheel so I tried to find good Silverlight tool which support basic drawing. I found some Silverlight tools which give me such basic drawing facility. Silver Draw (http://www.codeproject.com/KB/silverlight/silverdraw.aspx) seems more promising. Which give me all basic functionality with nice color picker also.  I can draw with Pen, Brush . Also I can draw line, rectangle and ellipse. This also give WPF duplex chatting and sharing facility. I did not need sharing facility so I omit this in my example.
image
Now It reduce my work and I only need to add eraser, undo , redo and save facility.

Eraser :

Eraser is simply drawing brush which used to draw ellipse with 25 width and height . Its color is same as background color so that user will think that it act as eraser.

case CurrentTool.EraseBrush:
{
HideVirtualLine();
var spot = toolHelper.CreateBrush(PrevPoint, cupt, 25);
(spot as Shape).StrokeThickness = 0;
(spot as Shape).Fill = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
_canvas.Children.Add(spot);
tempHolder.Add(spot as Shape);
//AddToUndoShape(spot as Shape);

PrevPoint = cupt;
break;

}

Undo, Redo :

Removing Line, Rectangle and Ellipse is easy because after mouse over this shape is added in canvas. But as pencil and brush do not have defined shape so line is created on every Mouse Move. But When user click on undo button I like to remove all pencil stroke that user draws at a time with mouse over. So I maintain another list for keeping every stroke on mouse move.


public Point DrawOnMove(Point cupt)
{
switch (tool)
{
case CurrentTool.Brush:
{
…….


break;

}

case CurrentTool.EraseBrush:
{
………..


break;

}
case CurrentTool.Pencil:
{
var pen = toolHelper.CreatePen(PrevPoint, cupt);
ApplyAttributes(pen as Shape);
(pen as Shape).StrokeThickness = 3;
_canvas.Children.Add(pen);
tempHolder.Add(pen as Shape);
PrevPoint = cupt;
break;
}
default:
………
}
return cupt;
}

here tempHolder contains every pencil stroke on mouse movement. And when user finish drawing with Mouse Over this collection is added to a dictionary  so that after clicking on undo, redo button this collection  is Added/Remove at a time.

public Point DrawOnComplete(Point cupt)
{
switch (tool)
{
case CurrentTool.Pen:
{
var pen = toolHelper.CreatePen(PrevPoint, cupt);
ApplyAttributes(pen as Shape);
_canvas.Children.Add(pen);
PrevPoint = cupt;
AddToUndoShape(pen as Shape);
break;

}

case CurrentTool.Rectangle:
{
……….;
break;
}
case CurrentTool.Ellipse:
{
……..


break;
}
case CurrentTool.Brush:
case CurrentTool.EraseBrush:
case CurrentTool.Pencil:
{
var shp = toolHelper.CreatePen(PrevPoint, cupt);
List<Shape> UnshapeList = new List<Shape>();
tempHolder.ForEach(p => UnshapeList.Add(p));
UnShapeDrawingItems.Add(shp as Shape, UnshapeList);
tempHolder.Clear();
AddToUndoShape(shp as Shape);
}
break;
}



return cupt;
}


 
Here for Pen, Rectangle and Ellipse, Shape is added to canvas and this shape is added to Undolist so that User can undo this Shape. But for Brush, EraseBrush and Pencil list of mouse


movement is added to a Dictionary by creating a virtual Pen as Key of Dictionary. This virtual Pen actually represent total mouse movement of Pencil/ Brush and this Pen is added to UndoList. 

My undo and redo list size is 400. When user click on Undo button UndoShape() function is called and when user click on redo then RedoShape() is called.For top item as Line/Ellipse and Rectangle


when user click on undo then this shape is removed from canvas and added to redo list. But for Pencil/Brush shape all strokes made by user before mouse over is removed from canvas at a time.


And the virtual Pen key item is added to redo list. RedoShape() function is completely opposite to UndoShape().


public void UndoShape()
{
if (undoTop > 0)
{
undoTop--;
Shape shape = UndoList[undoTop];
if (shape is Line && UnShapeDrawingItems.ContainsKey(shape))
{
foreach (var unShapeDrawingItem in UnShapeDrawingItems[shape])
{
_canvas.Children.Remove(unShapeDrawingItem);
}
}
else
_canvas.Children.Remove(shape);
UndoList.RemoveAt(undoTop);

AddToRedoList(shape);
}
}
public void RedoShape()
{
if (redoTop > 0)
{
redoTop--;
Shape shape = redoList[redoTop];
if (shape is Line && UnShapeDrawingItems.ContainsKey(shape))
{
foreach (var unShapeDrawingItem in UnShapeDrawingItems[shape])
{
_canvas.Children.Add(unShapeDrawingItem);
}
}
else
_canvas.Children.Add(shape);
redoList.RemoveAt(redoTop);
AddToUndoShape(shape);
}
}

private void AddToRedoList(Shape shape)
{
if (redoTop >= 400)
{
RemoveRedoBottom();
}
redoTop++;
redoList.Add(shape);
}

private void RemoveRedoBottom()
{
redoTop--;
redoList.RemoveAt(0);
}

public void AddToUndoShape(Shape shape)
{
if (undoTop >= 400)
{
RemoveUndoBottom();
}
undoTop++;
UndoList.Add(shape);

}

private void RemoveUndoBottom()
{
undoTop--;
UndoList.RemoveAt(0);
}


Saving as Image:

Now I have given Erase and Undo , Redo facility to user. And user want to save this created drawing in their server. I found an example (http://www.andybeaulieu.com/silverlight/3.0/printablesilverlight/printablesilverlight.aspx)where canvas is saved as PNG in postback. But the size of PNG is more than 2MB. I do not need so high quality image and want to reduce its size. So for image I prefer JPEG. I used FJ.Core dll for JPEG encoding as give in this stackoverflow (http://stackoverflow.com/questions/1139200/using-fjcore-to-encode-silverlight-writeablebitmap) . I also have reduced the size of image with ImageResizer.


private static string GetBase64Jpg(WriteableBitmap bitmap)
{
int width = bitmap.PixelWidth;
int height = bitmap.PixelHeight;
int bands = 3;
byte[][,] raster = new byte[bands][,];

for (int i = 0; i < bands; i++)
{
raster[i] = new byte[width, height];
}

for (int row = 0; row < height; row++)
{
for (int column = 0; column < width; column++)
{
int pixel = bitmap.Pixels[width * row + column];
raster[0][column, row] = (byte)(pixel >> 16);
raster[1][column, row] = (byte)(pixel >> 8);
raster[2][column, row] = (byte)pixel;
}
}

ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
MemoryStream stream = new MemoryStream();
ImageResizer resizer = new ImageResizer(img);
var resizedImage =resizer.Resize(300, 300,ResamplingFilters.NearestNeighbor);
JpegEncoder encoder = new JpegEncoder(resizedImage, 90, stream);
encoder.Encode();

stream.Seek(0, SeekOrigin.Begin);
byte[] binaryData = new Byte[stream.Length];
long bytesRead = stream.Read(binaryData, 0, (int)stream.Length);

string base64String =
System.Convert.ToBase64String(binaryData,
0,
binaryData.Length);

return base64String;
}

Now this whiteboard become a complete with Erase, Undo/ Redo and Save facility. You can find modified Silver Draw code with these feature in

http://dl.dropbox.com/u/20275838/SilverlightClient.rar



Tuesday, June 21, 2011

Writing Javascript in object oriented way : Namespace, Encapsulation : Public , Private , Static method

I used to develop a control which contain more than 6 tab and very tab contains control which work based on javascript functionality.My code became unmanageable and I decide to write my JavaScript code in object oriented way as I write my C# code. I found a code from codeproject for adding namespace in your code in good way.  I have share here the like of this article . http://www.codeproject.com/KB/scripting/jsnamespaces.aspx
So I created my class with name System.Classes.Placement as
registering that class in using.js
Namespace.Register("System.Classes.Placement");

and in my page
System.Classes.Placement = function () {
……
}
Now need some code public which will initialize jquery popup,  and register click handler. and also some Jquery drag drop code.
So I created functions for those function but those do not need to be public. I need only one Init() public function and CreateJqueryPopUp(), CreateDragable(), CreateDroppable() do not need to be public we can create them as private wich provide more encapsulation. So I created public public with return statement which is more readable. And other function are created before return statement.

So the function became like that
System.Classes.Placement = function () {
    var CreateJqueryPopUp =function()   {…..}
    var CreateDragable = function() {…..}
    var handleDropEvent = function(){….}
   return
  {
       init:function()
      {
        CreateJqueryPopUp ();
        CreateDragable();
      }
  };
}
and called the init() function in document ready method for initialization.
$(document).ready(function () {
            var placement = new System.Classes.Placement();            
            placement.init();
                   });
This words fine. But I also need function for deleting one item. as it would be on button click event and I do not like to create instance again for that to call RemoveItem method also I want RemoveItem method would be in that namespace. So for that I need to create a static method so that I can call this method like
onclick = "System.Classes.Placement.RemoveItem(this)"
Creating a static method is also easy. You need to define a method outside of class like
System.Classes.Placement=function(){
…..
   return{
     …
     };
}
System.Classes.Placement.RemoveItem =  function (div) {
            var parent = div.parentNode.parentNode;
            $(parent).empty();
            $(parent).removeClass('selected');
        }
So I got almost same flavor of Object oriented programing in javascript as in C# just with little convention. As much your code would be object oriented code would be more manageable.

Friday, May 27, 2011

ASP.NET server side handler for Valums Ajax file upload ; file uploader supports multiple file upload with progress bar , drag-and-drop

This ajax uploader uses XHR for uploading multiple files with progress-bar in FF3.6+, Safari4+, Chrome and falls back to hidden iframe based upload in other browsers, providing good user experience everywhere. You can also see php demo in Valums site http://valums.com/ajax-upload/
The current implementation has server side handler for java, php and Perl. But does not exist Asp.net handler. Here I have implemented a Asp.net handler for ajax file upload that supports  IE, Firefox and Chrome.
Problem is IE use context.Request.Files[] for sending file to server. But Firefox and Chrome use Context.Request.InputStream. So in handler you need to check both for reading stream.
For Firefox and Chrome you get fileName from header like
String filename = HttpContext.Current.Request.Headers["X-File-Name"];
Code that work in Firefox and Chrome
//This work for Firefox and Chrome.
Stream inputStream = HttpContext.Current.Request.InputStream;
FileStream fileStream = new FileStream(mapPath + "\\" + filename, FileMode.OpenOrCreate);
inputStream.CopyTo(fileStream);
fileStream.Close();
context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
But for IE you need to use
HttpPostedFile uploadedfile = context.Request.Files[0];
Code that work for IE browser :
HttpPostedFile uploadedfile = context.Request.Files[0];
filename = uploadedfile.FileName;
uploadedfile.SaveAs(mapPath + "\\" + filename);
context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
Here the response is send as JSON string and you will get JSON object as response. you need to send {success:true} to make ajax upload understand that file upload is successful otherwise you can send false.

Complete code is:
public void ProcessRequest(HttpContext context)
      {
          const string path = "Capture/Images";
          String filename = HttpContext.Current.Request.Headers["X-File-Name"];
          if (string.IsNullOrEmpty(filename) && HttpContext.Current.Request.Files.Count <= 0)
          {
              context.Response.Write("{success:false}");
          }
          else
          {
              string mapPath = HttpContext.Current.Server.MapPath(path);
              if (Directory.Exists(mapPath) == false)
              {
                  Directory.CreateDirectory(mapPath);
              }
              if (filename == null)
              {
                  //This work for IE
                  try
                  {
                      HttpPostedFile uploadedfile = context.Request.Files[0];
                      filename = uploadedfile.FileName;
                      uploadedfile.SaveAs(mapPath + "\\" + filename);
                      context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
                  }
                  catch (Exception)
                  {
                      context.Response.Write("{success:false}");
                  }
              }
              else
              {
                  //This work for Firefox and Chrome.
                  FileStream fileStream = new FileStream(mapPath + "\\" + filename, FileMode.OpenOrCreate);
                  try
                  {
                      Stream inputStream = HttpContext.Current.Request.InputStream;
                      inputStream.CopyTo(fileStream);
                      context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
                  }
                  catch (Exception)
                  {
                      context.Response.Write("{success:false}");
                  }
                  finally
                  {
                      fileStream.Close();
                  }
              }
          }
      }

Complete solution is available in codeproject http://www.codeproject.com/KB/aspnet/AspNetHandlerAjaxUpload.aspx

Saturday, May 14, 2011

JQuery context menu items active/ deactivate for .NET TreeView

I was needed to give some functionality to .NET tree view for user so that user can add, edit, activate or deactivate node. Jquery context menu is very nice and give me functionality to customize context menu according to my requirement. My requirement was to make some items active based on image of treeview. .NET treeview use table structure. if the node contain is <td> wich id is ‘xyz_01’ then image <td> id will be ‘xyz_01i’ . Based on this I find the image element and according to source of image I have changed the active menu items on mousedown event. MouseDown event work before displaying jquery context menu. The code is given here.

Context menu div is

<ul id="myMenu" class="contextMenu"> 
<li class="copy"><a href="#add">Add</a></li>
<li class="edit"><a href="#edit">Edit</a></li>
<li class="inactive"><a href="#Inactive">Inactivate</a></li>
<li class="active"><a href="#Active">Activate</a></li>
<li class="quit separator"><a href="#cancel">Cancel</a></li>
</ul>



The mouse down code for activate and deactive element according to treeview image source.




$("#MyTreeDiv A").mousedown(function () { 
var itemId = $(this).attr('id');
var imageItemId = itemId + 'i';

var img = $('#' + imageItemId).children('img').first();
var s = $(img).attr('src');
if (s.indexOf('inactive') > -1) {
$('#myMenu').enableContextMenuItems('#Active');
$('#myMenu').disableContextMenuItems('#Inactive');
$('#myMenu').disableContextMenuItems('#add');
$('#myMenu').disableContextMenuItems('#edit');
}
else if (s.indexOf('active') > -1) {

$('#myMenu').disableContextMenuItems('#Active');
$('#myMenu').enableContextMenuItems('#Inactive');
$('#myMenu').enableContextMenuItems('#add');
$('#myMenu').enableContextMenuItems('#edit');
}

});

Tuesday, February 15, 2011

WPF: Textblock vertical alignment with given height

I was needed to set the alignment of textblock in center and also need to set height which is greater than normal textblock text height. But problem is when the text height is assigned then vertical alignment of textblock does not work. To solve this problem easy way to set padding so that the textblock text remain at center position. For that you need to measure the height of textblock before setting the custom height of textblock. After getting the desiredsize of textblock you can calculate the top padding of text in textblock. Then set the padding and custom height of textblock. This will solve the problem of making text position at center giving custom height.
textBlock.Measure(new Size(infiniteWidth, infiniteHeight));
var textBlockHeight = textBlock.DesiredSize.Height;
var textBlockTopPaddig = (CustomHeight - textBlockHeight)/2;
textBlock.Padding = new Thickness(0,textBlockTopPaddig,0,0);
textBlock.Height = CustomHeight;
 
XAML 
But if you want to set the custom height of TextBox from XAML then create a StackPanel and set the TextBlock inside that StackPanel. Instead of setting TextBlock height set the height of StackPanel and set StackPanel vertical alignment as VerticalAlignment.Center. So now textblock will be displayed in center of StackPanel.