3
\$\begingroup\$

I have written a VB.NET function that takes a byte array, a starting position (in bits), and a number of bits as input. The goal is to remove any occurrences of 3 from the specified range being searched. The function should return the new byte array with the specified length and the information about how many bytes were skipped.

Example: Given the byte array {103, 100, 0, 51, 172, 217, 0, 113, 1, 83, 229, 188, 4, 64, 0, 0, 3, 0, 64, 0, 0, 15, 3, 198, 12, 101, 128}, the starting position (in bits) is 106, and the number of bits is 32. The function should then return {64, 0, 0, 0, 64} (note the skipped 3) and a value of 1. There are 40 bits here, instead of the 32 specified, because the last byte has already started or because the starting position in bits was not aligned to bit position 0. The function should also return the number of skipped bytes so that I can update the position in the bitstream accordingly.

Edge case: If the last read byte is a 3, and it is partially read, it should not be skipped.

The original byte array must not be modified.

I quickly wrote the function a while ago, and it works. However, I am posting this on CodeReview to get suggestions to increase the cpu performance.

The use case is parsing specific items in H.264. Occasionally, there are threes between zero-bytes so that the decoder does not confuse the zero-bytes with a new frame (to put it simply).

I created a test project for you:

Option Strict On
Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms
Friend NotInheritable Class FormMain
 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
 Dim byteArray As Byte() = New List(Of Byte)() From {103, 100, 0, 51, 172, 217, 0, 113, 1, 83, 229, 188, 4, 64, 0, 0, 3, 0, 64, 0, 0, 15, 3, 198, 12, 101, 128}.ToArray()
 Dim result As (Byte(), Integer) = ExtractRelevantBytesWithout3(byteArray, 106, 32)
 End Sub
 Private Shared Function ExtractRelevantBytesWithout3(byteArray As Byte(), bitStartPosition As Integer, bitCount As Integer) As (Byte(), numberOfSkippedBytes As Integer)
 Dim result As New List(Of Byte)()
 Dim bitsRemaining As Integer = bitCount
 Dim currentBitPosition As Integer = bitStartPosition
 Dim numberOfSkippedBytes As Integer = 0
 Dim increaseOnce As Boolean = True
 While bitsRemaining > 0 AndAlso currentBitPosition \ 8 < byteArray.Length
 Dim currentByteIndex As Integer = currentBitPosition \ 8
 Dim bitIndexWithinByte As Integer = currentBitPosition Mod 8
 If bitIndexWithinByte > 0 AndAlso increaseOnce Then
 bitsRemaining += 8
 increaseOnce = False
 End If
 Dim currentByte As Byte = byteArray(currentByteIndex)
 If currentByte = CByte(3) AndAlso bitsRemaining > 8 Then ' bitsRemaining > 8 means: Do not skip if the 3 is not read completely.
 currentBitPosition += 8 ' Skip to the next byte
 numberOfSkippedBytes += 1
 Continue While
 End If
 result.Add(currentByte)
 currentBitPosition += 8
 bitsRemaining -= Math.Min(bitsRemaining, 8) ' Deduct processed bits
 End While
 Return (result.ToArray(), numberOfSkippedBytes)
 End Function
End Class
pacmaninbw
26.1k13 gold badges47 silver badges114 bronze badges
asked Dec 22, 2024 at 16:05
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Rather than adding the test code to the current question that has already been answered as a follow up question with a link back to this question. Please do not edit the question, especially the code, after an answer has been posted. Changing the question may cause answer invalidation. Everyone needs to be able to see what the reviewer was referring to. What to do after the question has been answered. \$\endgroup\$ Commented Jan 5 at 14:03
  • \$\begingroup\$ @pacmaninbw Ok, sure! \$\endgroup\$ Commented Jan 5 at 14:18

1 Answer 1

3
\$\begingroup\$

A couple of comments.

  1. You have no unit tests
  2. This class should not be in a forms class, it should have nothing to do with the UI at all. It may get called from the UI but it should of itself have no connection to it. If you want to make it runnable, for the readers of this question, use two classes, one of which is your actual class and one of which is the main from a console application.
  3. Your return tuple shouldn't include a Byte(), but instead a List(Of Byte)
  4. Option Infer should be on and you should make heavy use of Dim. (this is more opinion based than the others, but IMO the extra type specification doesn't add anything to the code)
  5. Finally, I would use a constant for CByte(3) instead of hard coding it into the equation. Not really a big deal, but finding a name instead of a value is always a lot easier. And if you do search for it by CByte(3) you'll still find it.
answered Jan 5 at 1:47
\$\endgroup\$
2
  • \$\begingroup\$ Hello, @jmoreno, 1) I have now written unit tests and have added them here, with a small adjustment in the function. 2) I am aware that one does not leave a function like this in the FormMain. It is a small separate project for you to use the code. However, due to the unit tests, the function has been moved to a separate class. 3) I have to return a byte array because it is used in other functions. Thank you for your answer :) \$\endgroup\$ Commented Jan 5 at 10:41
  • \$\begingroup\$ @Daniel: even if it is used as a byte array in other functions, they can easily do that transformation. This function mainly deals with the data as a List, also you might try to take/return an IList(Of Byte). From the class definition... Single-dimensional arrays implement the System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyList<T> and System.Collections.Generic.IReadOnlyCollection<T> generic interfaces. \$\endgroup\$ Commented Jan 5 at 14:59

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.