public static void collectPayPalDeviceData(final BraintreeFragment fragment, final BraintreeResponseListener<String> listener) {
        final JSONObject deviceData = new JSONObject();

        try {
            String clientMetadataId = getPayPalClientMetadataId(fragment.getApplicationContext());
            if (!TextUtils.isEmpty(clientMetadataId)) {
                deviceData.put(CORRELATION_ID_KEY, clientMetadataId);
            }
        } catch (JSONException ignored) {}

        listener.onResponse(deviceData.toString());
    }

public static void collectPayPalDeviceData ( final BraintreeFragment fragment , final BraintreeResponseListener < String > listener ) { final JSONObject deviceData = new JSONObject ( ) ; try { String clientMetadataId = getPayPalClientMetadataId ( fragment . getApplicationContext ( ) ) ; if ( ! TextUtils . isEmpty ( clientMetadataId ) ) { deviceData . put ( CORRELATION_ID_KEY , clientMetadataId ) ; } } catch ( JSONException ignored ) { } listener . onResponse ( deviceData . toString ( ) ) ; }

Collect PayPal device information for fraud identification purposes.

@param fragment {@link BraintreeFragment}
@param listener listener to be called with the device data String to send to Braintree.

Collect PayPal device information for fraud identification purposes .


public static String getPayPalClientMetadataId(Context context) {
        try {
            return PayPalOneTouchCore.getClientMetadataId(context);
        } catch (NoClassDefFoundError ignored) {}

        try {
            return PayPalDataCollector.getClientMetadataId(context);
        } catch (NoClassDefFoundError ignored) {}

        return "";
    }

public static String getPayPalClientMetadataId ( Context context ) { try { return PayPalOneTouchCore . getClientMetadataId ( context ) ; } catch ( NoClassDefFoundError ignored ) { } try { return PayPalDataCollector . getClientMetadataId ( context ) ; } catch ( NoClassDefFoundError ignored ) { } return "" ; }

Collect device information for fraud identification purposes from PayPal only.

@param context A valid {@link Context}
@return The client metadata id associated with the collected data.

Collect device information for fraud identification purposes from PayPal only .


@SuppressLint("PackageManagerGetSignatures")
    public static boolean isSignatureValid(Context context, String packageName,
            String certificateSubject, String certificateIssuer, int publicKeyHashCode) {
        if (!sEnableSignatureVerification) {
            return true;
        }

        PackageManager packageManager = context.getPackageManager();
        Signature[] signatures;
        try {
            signatures = packageManager
                    .getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
        } catch (NameNotFoundException e) {
            return false;
        }

        InputStream certStream = null;
        boolean validated = (signatures.length != 0);
        for (Signature signature : signatures) {
            try {
                certStream = new ByteArrayInputStream(signature.toByteArray());

                X509Certificate x509Cert =
                        (X509Certificate) CertificateFactory.getInstance("X509")
                                .generateCertificate(certStream);

                String subject = x509Cert.getSubjectX500Principal().getName();
                String issuer = x509Cert.getIssuerX500Principal().getName();
                int actualPublicKeyHashCode = x509Cert.getPublicKey().hashCode();

                validated &= (certificateSubject.equals(subject) &&
                        certificateIssuer.equals(issuer) &&
                        publicKeyHashCode == actualPublicKeyHashCode);

                if (!validated) {
                    return false;
                }
            } catch (CertificateException e) {
                return false;
            } finally {
                try {
                    if (certStream != null) {
                        certStream.close();
                    }
                } catch(IOException ignored) {}
            }
        }

        return validated;
    }

@ SuppressLint ( "PackageManagerGetSignatures" ) public static boolean isSignatureValid ( Context context , String packageName , String certificateSubject , String certificateIssuer , int publicKeyHashCode ) { if ( ! sEnableSignatureVerification ) { return true ; } PackageManager packageManager = context . getPackageManager ( ) ; Signature [ ] signatures ; try { signatures = packageManager . getPackageInfo ( packageName , PackageManager . GET_SIGNATURES ) . signatures ; } catch ( NameNotFoundException e ) { return false ; } InputStream certStream = null ; boolean validated = ( signatures . length != 0 ) ; for ( Signature signature : signatures ) { try { certStream = new ByteArrayInputStream ( signature . toByteArray ( ) ) ; X509Certificate x509Cert = ( X509Certificate ) CertificateFactory . getInstance ( "X509" ) . generateCertificate ( certStream ) ; String subject = x509Cert . getSubjectX500Principal ( ) . getName ( ) ; String issuer = x509Cert . getIssuerX500Principal ( ) . getName ( ) ; int actualPublicKeyHashCode = x509Cert . getPublicKey ( ) . hashCode ( ) ; validated &= ( certificateSubject . equals ( subject ) && certificateIssuer . equals ( issuer ) && publicKeyHashCode == actualPublicKeyHashCode ) ; if ( ! validated ) { return false ; } } catch ( CertificateException e ) { return false ; } finally { try { if ( certStream != null ) { certStream . close ( ) ; } } catch ( IOException ignored ) { } } } return validated ; }

Check if an app has the correct, matching, signature. Used to prevent malicious apps from
impersonating other apps.

@param context
@param packageName the package name of the app to verify.
@param certificateSubject the expected certificate subject of the app.
@param certificateIssuer the expected certificate issuer of the app.
@param publicKeyHashCode the hash code of the app's public key.
@return true is signature is valid or signature verification has been disabled.

Check if an app has the correct matching signature . Used to prevent malicious apps from impersonating other apps .


public static String optString(JSONObject json, String name, String fallback) {
        if (json.isNull(name)) {
            return fallback;
        } else {
            return json.optString(name, fallback);
        }
    }

public static String optString ( JSONObject json , String name , String fallback ) { if ( json . isNull ( name ) ) { return fallback ; } else { return json . optString ( name , fallback ) ; } }

Returns the value mapped by name if it exists, coercing it if necessary, or fallback if no such mapping exists.

This is a work around for http://code.google.com/p/android/issues/detail?id=13830 returning "null" if the json
value is null.

@param json
@param name
@param fallback
@return {@link String}

Returns the value mapped by name if it exists coercing it if necessary or fallback if no such mapping exists .


public static List<PaymentMethodNonce> parsePaymentMethodNonces(String jsonBody)
            throws JSONException {
        JSONArray paymentMethods = new JSONObject(jsonBody).getJSONArray(
                PAYMENT_METHOD_NONCE_COLLECTION_KEY);

        if (paymentMethods == null) {
            return Collections.emptyList();
        }

        List<PaymentMethodNonce> paymentMethodsNonces = new ArrayList<>();
        JSONObject json;
        PaymentMethodNonce paymentMethodNonce;
        for(int i = 0; i < paymentMethods.length(); i++) {
            json = paymentMethods.getJSONObject(i);
            paymentMethodNonce = parsePaymentMethodNonces(json,
                    json.getString(PAYMENT_METHOD_TYPE_KEY));
            if (paymentMethodNonce != null) {
                paymentMethodsNonces.add(paymentMethodNonce);
            }
        }

        return paymentMethodsNonces;
    }

public static List < PaymentMethodNonce > parsePaymentMethodNonces ( String jsonBody ) throws JSONException { JSONArray paymentMethods = new JSONObject ( jsonBody ) . getJSONArray ( PAYMENT_METHOD_NONCE_COLLECTION_KEY ) ; if ( paymentMethods == null ) { return Collections . emptyList ( ) ; } List < PaymentMethodNonce > paymentMethodsNonces = new ArrayList <> ( ) ; JSONObject json ; PaymentMethodNonce paymentMethodNonce ; for ( int i = 0 ; i < paymentMethods . length ( ) ; i ++ ) { json = paymentMethods . getJSONObject ( i ) ; paymentMethodNonce = parsePaymentMethodNonces ( json , json . getString ( PAYMENT_METHOD_TYPE_KEY ) ) ; if ( paymentMethodNonce != null ) { paymentMethodsNonces . add ( paymentMethodNonce ) ; } } return paymentMethodsNonces ; }

Parses a response from the Braintree gateway for a list of payment method nonces.

@param jsonBody Json-formatted String containing a list of {@link PaymentMethodNonce}s
@return List of {@link PaymentMethodNonce}s contained in jsonBody
@throws JSONException

Parses a response from the Braintree gateway for a list of payment method nonces .


public CheckoutRecipe getBrowserCheckoutConfig() {
        for (CheckoutRecipe recipe : mCheckoutRecipesInDecreasingPriorityOrder) {
            if (recipe.getTarget() == RequestTarget.browser) {
                return recipe;
            }
        }

        return null;
    }

Returns the browser recipe that can handle checkout, or null if there is none.

@return

Returns the browser recipe that can handle checkout or null if there is none .


public BillingAgreementRecipe getBrowserBillingAgreementConfig() {
        for (BillingAgreementRecipe recipe : mBillingAgreementRecipesInDecreasingPriorityOrder) {
            if (recipe.getTarget() == RequestTarget.browser) {
                return recipe;
            }
        }

        return null;
    }

Returns the browser recipe that can handle billing agreement, or null if there is none.

@return

Returns the browser recipe that can handle billing agreement or null if there is none .


public void get(final String path, final HttpResponseCallback callback) {
        if (path == null) {
            postCallbackOnMainThread(callback, new IllegalArgumentException("Path cannot be null"));
            return;
        }

        final String url;
        if (path.startsWith("http")) {
            url = path;
        } else {
            url = mBaseUrl + path;
        }

        mThreadPool.submit(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    connection = init(url);
                    connection.setRequestMethod(METHOD_GET);
                    postCallbackOnMainThread(callback, parseResponse(connection));
                } catch (Exception e) {
                    postCallbackOnMainThread(callback, e);
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        });
    }

public
void
get
(
final
String
path
,
final
HttpResponseCallback
callback
)
{
if
(
path
==
)
{
postCallbackOnMainThread
(
callback
,
new
IllegalArgumentException
(
"Path cannot be null"
)
)
;
return
;
}
final
String
url
;
if
(
path
.
startsWith
(
"http"
)
)
{
url
=
path
;
}
else
{
url
=
mBaseUrl
+
path
;
}
mThreadPool
.
submit
(
new
Runnable
(
)
{
@
Override
public
void
run
(
)
{
HttpURLConnection
connection
=
;
try
{
connection
=
init
(
url
)
;
connection
.
setRequestMethod
(
METHOD_GET
)
;
postCallbackOnMainThread
(
callback
,
parseResponse
(
connection
)
)
;
}
catch
(
Exception
e
)
{
postCallbackOnMainThread
(
callback
,
e
)
;
}
finally
{
if
(
connection
!=
)
{
connection
.
disconnect
(
)
;
}
}
}
}
)
;
}

Make a HTTP GET request to using the base url and path provided. If the path is a full url,
it will be used instead of the previously provided base url.

@param path The path or url to request from the server via GET
@param callback The {@link HttpResponseCallback} to receive the response or error.

Make a HTTP GET request to using the base url and path provided . If the path is a full url it will be used instead of the previously provided base url .


public void post(final String path, final String data, final HttpResponseCallback callback) {
        if (path == null) {
            postCallbackOnMainThread(callback, new IllegalArgumentException("Path cannot be null"));
            return;
        }

        mThreadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    postCallbackOnMainThread(callback, post(path, data));
                } catch (Exception e) {
                    postCallbackOnMainThread(callback, e);
                }
            }
        });
    }

public
void
post
(
final
String
path
,
final
String
data
,
final
HttpResponseCallback
callback
)
{
if
(
path
==
)
{
postCallbackOnMainThread
(
callback
,
new
IllegalArgumentException
(
"Path cannot be null"
)
)
;
return
;
}
mThreadPool
.
submit
(
new
Runnable
(
)
{
@
Override
public
void
run
(
)
{
try
{
postCallbackOnMainThread
(
callback
,
post
(
path
,
data
)
)
;
}
catch
(
Exception
e
)
{
postCallbackOnMainThread
(
callback
,
e
)
;
}
}
}
)
;
}

Make a HTTP POST request using the base url and path provided. If the path is a full url,
it will be used instead of the previously provided url.

@param path The path or url to request from the server via HTTP POST
@param data The body of the POST request
@param callback The {@link HttpResponseCallback} to receive the response or error.

Make a HTTP POST request using the base url and path provided . If the path is a full url it will be used instead of the previously provided url .


public String post(String path, String data) throws Exception {
        HttpURLConnection connection = null;
        try {
            if (path.startsWith("http")) {
                connection = init(path);
            } else {
                connection = init(mBaseUrl + path);
            }

            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestMethod(METHOD_POST);
            connection.setDoOutput(true);

            writeOutputStream(connection.getOutputStream(), data);

            return parseResponse(connection);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

public String post ( String path , String data ) throws Exception { HttpURLConnection connection = null ; try { if ( path . startsWith ( "http" ) ) { connection = init ( path ) ; } else { connection = init ( mBaseUrl + path ) ; } connection . setRequestProperty ( "Content-Type" , "application/json" ) ; connection . setRequestMethod ( METHOD_POST ) ; connection . setDoOutput ( true ) ; writeOutputStream ( connection . getOutputStream ( ) , data ) ; return parseResponse ( connection ) ; } finally { if ( connection != null ) { connection . disconnect ( ) ; } } }

Performs a synchronous post request.

@param path the path or url to request from the server via HTTP POST
@param data the body of the post request
@return The HTTP body the of the response

@see HttpClient#post(String, String, HttpResponseCallback)
@throws Exception


public static void startPayment(final BraintreeFragment fragment, final LocalPaymentRequest request,
            final BraintreeResponseListener<LocalPaymentRequest> listener) {
        if (request == null) {
            fragment.postCallback(new BraintreeException("A LocalPaymentRequest is required."));
            return;
        } else if (request.getApprovalUrl() != null || request.getPaymentId() != null) {
            fragment.postCallback(new BraintreeException("LocalPaymentRequest is invalid, " +
                    "appovalUrl and paymentId should not be set."));
            return;
        } else if (request.getPaymentType() == null || request.getAmount() == null) {
            fragment.postCallback(new BraintreeException("LocalPaymentRequest is invalid, " +
                    "paymentType and amount are required."));
            return;
        } else if (listener == null) {
            fragment.postCallback(new BraintreeException("BraintreeResponseListener<LocalPaymentRequest> " +
                    "is required."));
            return;
        }

        fragment.waitForConfiguration(new ConfigurationListener() {
            @Override
            public void onConfigurationFetched(Configuration configuration) {
                if (!configuration.getPayPal().isEnabled()) {
                    fragment.postCallback(new ConfigurationException("Local payments are not enabled for this merchant."));
                    return;
                }

                sMerchantAccountId = request.getMerchantAccountId();
                sPaymentType = request.getPaymentType();
                String returnUrl =  fragment.getReturnUrlScheme() + "://" + LOCAL_PAYMENT_SUCCESSS;
                String cancel =  fragment.getReturnUrlScheme() + "://" + LOCAL_PAYMENT_CANCEL;

                fragment.sendAnalyticsEvent(paymentTypeForAnalytics() + ".local-payment.start-payment.selected");

                fragment.getHttpClient().post("/v1/paypal_hermes/create_payment_resource", request.build(returnUrl, cancel),
                        new HttpResponseCallback() {
                            @Override
                            public void success(String responseBody) {
                                try {
                                    JSONObject responseJson = new JSONObject(responseBody);
                                    request.approvalUrl(responseJson.getJSONObject("paymentResource").getString("redirectUrl"));
                                    request.paymentId(responseJson.getJSONObject("paymentResource").getString("paymentToken"));

                                    fragment.sendAnalyticsEvent(paymentTypeForAnalytics() + ".local-payment.create.succeeded");
                                    listener.onResponse(request);

                                } catch (JSONException jsonException) {
                                    failure(jsonException);
                                }
                            }

                            @Override
                            public void failure(Exception exception) {
                                fragment.sendAnalyticsEvent(paymentTypeForAnalytics() + ".local-payment.webswitch.initiate.failed");
                                fragment.postCallback(exception);
                            }
                        });
            }
        });
    }

Prepares the payment flow for a specific type of local payment.

@param fragment {@link BraintreeFragment}
@param request {@link LocalPaymentRequest} with the payment details.
@param listener {@link BraintreeResponseListener} the callback to which the {@link LocalPaymentRequest} will be sent
with a payment ID for preprocessing and an approval URL. Once ready, use {@link #approvePayment(BraintreeFragment, LocalPaymentRequest)}
to initiate the browser switch.

Prepares the payment flow for a specific type of local payment .


public static void approvePayment(BraintreeFragment fragment, LocalPaymentRequest request) {
        fragment.browserSwitch(BraintreeRequestCodes.LOCAL_PAYMENT, request.getApprovalUrl());
        fragment.sendAnalyticsEvent(paymentTypeForAnalytics() + ".local-payment.webswitch.initiate.succeeded");
    }

Initiates the browser switch for a payment flow by opening a browser where the customer can authenticate with their bank.

@param fragment {@link BraintreeFragment}
@param request {@link LocalPaymentRequest} which has already been sent to {@link #startPayment(BraintreeFragment, LocalPaymentRequest, BraintreeResponseListener)}
and now has an approvalUrl and paymentId.

Initiates the browser switch for a payment flow by opening a browser where the customer can authenticate with their bank .


public <T extends BraintreeListener> void addListener(T listener) {
        if (listener instanceof ConfigurationListener) {
            mConfigurationListener = (ConfigurationListener) listener;
        }

        if (listener instanceof BraintreeCancelListener) {
            mCancelListener = (BraintreeCancelListener) listener;
        }

        if (listener instanceof PaymentMethodNoncesUpdatedListener) {
            mPaymentMethodNoncesUpdatedListener = (PaymentMethodNoncesUpdatedListener) listener;
        }

        if (listener instanceof PaymentMethodNonceCreatedListener) {
            mPaymentMethodNonceCreatedListener = (PaymentMethodNonceCreatedListener) listener;
        }

        if (listener instanceof PaymentMethodNonceDeletedListener) {
            mPaymentMethodNonceDeletedListener = (PaymentMethodNonceDeletedListener) listener;
        }

        if (listener instanceof BraintreePaymentResultListener) {
            mBraintreePaymentResultListener = (BraintreePaymentResultListener) listener;
        }

        if (listener instanceof BraintreeErrorListener) {
            mErrorListener = (BraintreeErrorListener) listener;
        }

        if (listener instanceof UnionPayListener) {
            mUnionPayListener = (UnionPayListener) listener;
        }

        if (listener instanceof AmericanExpressListener) {
            mAmericanExpressListener = (AmericanExpressListener) listener;
        }

        flushCallbacks();
    }

public < T extends BraintreeListener > void addListener ( T listener ) { if ( listener instanceof ConfigurationListener ) { mConfigurationListener = ( ConfigurationListener ) listener ; } if ( listener instanceof BraintreeCancelListener ) { mCancelListener = ( BraintreeCancelListener ) listener ; } if ( listener instanceof PaymentMethodNoncesUpdatedListener ) { mPaymentMethodNoncesUpdatedListener = ( PaymentMethodNoncesUpdatedListener ) listener ; } if ( listener instanceof PaymentMethodNonceCreatedListener ) { mPaymentMethodNonceCreatedListener = ( PaymentMethodNonceCreatedListener ) listener ; } if ( listener instanceof PaymentMethodNonceDeletedListener ) { mPaymentMethodNonceDeletedListener = ( PaymentMethodNonceDeletedListener ) listener ; } if ( listener instanceof BraintreePaymentResultListener ) { mBraintreePaymentResultListener = ( BraintreePaymentResultListener ) listener ; } if ( listener instanceof BraintreeErrorListener ) { mErrorListener = ( BraintreeErrorListener ) listener ; } if ( listener instanceof UnionPayListener ) { mUnionPayListener = ( UnionPayListener ) listener ; } if ( listener instanceof AmericanExpressListener ) { mAmericanExpressListener = ( AmericanExpressListener ) listener ; } flushCallbacks ( ) ; }

Adds a listener.

@param listener the listener to add.


public <T extends BraintreeListener> void removeListener(T listener) {
        if (listener instanceof ConfigurationListener) {
            mConfigurationListener = null;
        }

        if (listener instanceof BraintreeCancelListener) {
            mCancelListener = null;
        }

        if (listener instanceof PaymentMethodNoncesUpdatedListener) {
            mPaymentMethodNoncesUpdatedListener = null;
        }

        if (listener instanceof PaymentMethodNonceCreatedListener) {
            mPaymentMethodNonceCreatedListener = null;
        }

        if (listener instanceof PaymentMethodNonceDeletedListener) {
            mPaymentMethodNonceDeletedListener = null;
        }

        if (listener instanceof BraintreePaymentResultListener) {
            mBraintreePaymentResultListener = null;
        }

        if (listener instanceof BraintreeErrorListener) {
            mErrorListener = null;
        }

        if (listener instanceof UnionPayListener) {
            mUnionPayListener = null;
        }

        if (listener instanceof AmericanExpressListener) {
            mAmericanExpressListener = null;
        }
    }

public < T extends BraintreeListener > void removeListener ( T listener ) { if ( listener instanceof ConfigurationListener ) { mConfigurationListener = null ; } if ( listener instanceof BraintreeCancelListener ) { mCancelListener = null ; } if ( listener instanceof PaymentMethodNoncesUpdatedListener ) { mPaymentMethodNoncesUpdatedListener = null ; } if ( listener instanceof PaymentMethodNonceCreatedListener ) { mPaymentMethodNonceCreatedListener = null ; } if ( listener instanceof PaymentMethodNonceDeletedListener ) { mPaymentMethodNonceDeletedListener = null ; } if ( listener instanceof BraintreePaymentResultListener ) { mBraintreePaymentResultListener = null ; } if ( listener instanceof BraintreeErrorListener ) { mErrorListener = null ; } if ( listener instanceof UnionPayListener ) { mUnionPayListener = null ; } if ( listener instanceof AmericanExpressListener ) { mAmericanExpressListener = null ; } }

Removes a previously added listener.

@param listener the listener to remove.


public static void requestBillingAgreement(BraintreeFragment fragment, PayPalRequest request,
            PayPalApprovalHandler handler) {
        if (request.getAmount() == null) {
            fragment.sendAnalyticsEvent("paypal.billing-agreement.selected");
            if (request.shouldOfferCredit()) {
                fragment.sendAnalyticsEvent("paypal.billing-agreement.credit.offered");
            }

            requestOneTimePayment(fragment, request, true, handler);
        } else {
            fragment.postCallback(new BraintreeException(
                    "There must be no amount specified for the Billing Agreement flow"));
        }
    }

Starts the Billing Agreement flow for PayPal with custom PayPal approval handler.

@param fragment A {@link BraintreeFragment} used to process the request.
@param request A {@link PayPalRequest} used to customize the request.
@param handler A {@link PayPalApprovalHandler} for custom approval handling.

Starts the Billing Agreement flow for PayPal with custom PayPal approval handler .


protected static void onActivityResult(final BraintreeFragment fragment, int resultCode, Intent data) {
        Request request = getPersistedRequest(fragment.getApplicationContext());
        String paymentType = paymentTypeForRequest(request);
        String switchType = switchTypeForIntent(data);
        String eventPrefix = paymentType + "." + switchType;

        if (resultCode == AppCompatActivity.RESULT_OK && data != null && request != null) {
            Result result = PayPalOneTouchCore.parseResponse(fragment.getApplicationContext(), request, data);
            switch (result.getResultType()) {
                case Error:
                    fragment.postCallback(new BrowserSwitchException(result.getError().getMessage()));
                    fragment.sendAnalyticsEvent(eventPrefix + ".failed");
                    break;
                case Cancel:
                    fragment.postCancelCallback(BraintreeRequestCodes.PAYPAL);
                    fragment.sendAnalyticsEvent(eventPrefix + ".canceled");
                    break;
                case Success:
                    onSuccess(fragment, data, request, result);
                    fragment.sendAnalyticsEvent(eventPrefix + ".succeeded");
                    break;
            }
        } else {
            fragment.sendAnalyticsEvent(eventPrefix + ".canceled");

            if (resultCode != AppCompatActivity.RESULT_CANCELED) {
                fragment.postCancelCallback(BraintreeRequestCodes.PAYPAL);
            }
        }
    }

protected static void onActivityResult ( final BraintreeFragment fragment , int resultCode , Intent data ) { Request request = getPersistedRequest ( fragment . getApplicationContext ( ) ) ; String paymentType = paymentTypeForRequest ( request ) ; String switchType = switchTypeForIntent ( data ) ; String eventPrefix = paymentType + "." + switchType ; if ( resultCode == AppCompatActivity . RESULT_OK && data != null && request != null ) { Result result = PayPalOneTouchCore . parseResponse ( fragment . getApplicationContext ( ) , request , data ) ; switch ( result . getResultType ( ) ) { case Error : fragment . postCallback ( new BrowserSwitchException ( result . getError ( ) . getMessage ( ) ) ) ; fragment . sendAnalyticsEvent ( eventPrefix + ".failed" ) ; break ; case Cancel : fragment . postCancelCallback ( BraintreeRequestCodes . PAYPAL ) ; fragment . sendAnalyticsEvent ( eventPrefix + ".canceled" ) ; break ; case Success : onSuccess ( fragment , data , request , result ) ; fragment . sendAnalyticsEvent ( eventPrefix + ".succeeded" ) ; break ; } } else { fragment . sendAnalyticsEvent ( eventPrefix + ".canceled" ) ; if ( resultCode != AppCompatActivity . RESULT_CANCELED ) { fragment . postCancelCallback ( BraintreeRequestCodes . PAYPAL ) ; } } }

The result from PayPal's request.

@param fragment A {@link BraintreeFragment} used to process the request.
@param data Data associated with the result.


private static PayPalAccountBuilder parseResponse(PayPalRequest paypalRequest, Request request, Result result,
            Intent intent) {
        PayPalAccountBuilder paypalAccountBuilder = new PayPalAccountBuilder()
                .clientMetadataId(request.getClientMetadataId());

        if (paypalRequest != null && paypalRequest.getMerchantAccountId() != null) {
            paypalAccountBuilder.merchantAccountId(paypalRequest.getMerchantAccountId());
        }

        if (request instanceof CheckoutRequest && paypalRequest != null) {
            paypalAccountBuilder.intent(paypalRequest.getIntent());
        }

        if (isAppSwitch(intent)) {
            paypalAccountBuilder.source("paypal-app");
        } else {
            paypalAccountBuilder.source("paypal-browser");
        }

        paypalAccountBuilder.oneTouchCoreData(result.getResponse());

        return paypalAccountBuilder;
    }

private static PayPalAccountBuilder parseResponse ( PayPalRequest paypalRequest , Request request , Result result , Intent intent ) { PayPalAccountBuilder paypalAccountBuilder = new PayPalAccountBuilder ( ) . clientMetadataId ( request . getClientMetadataId ( ) ) ; if ( paypalRequest != null && paypalRequest . getMerchantAccountId ( ) != null ) { paypalAccountBuilder . merchantAccountId ( paypalRequest . getMerchantAccountId ( ) ) ; } if ( request instanceof CheckoutRequest && paypalRequest != null ) { paypalAccountBuilder . intent ( paypalRequest . getIntent ( ) ) ; } if ( isAppSwitch ( intent ) ) { paypalAccountBuilder . source ( "paypal-app" ) ; } else { paypalAccountBuilder . source ( "paypal-browser" ) ; } paypalAccountBuilder . oneTouchCoreData ( result . getResponse ( ) ) ; return paypalAccountBuilder ; }

Parse the PayPal response URL using OneTouchCore.

@param paypalRequest Original {@link PayPalRequest} that started this flow.
@param result Context that received the result.
@param intent The {@link Intent} returned in result.
@return A {@link PayPalAccountBuilder} or null if the intent is invalid.

Parse the PayPal response URL using OneTouchCore .


public static void addNounsToDictionary(List<String> words) {
    OpenKoreanTextProcessor.addNounsToDictionary(JavaConverters.asScalaBufferConverter(words).asScala());
  }

public static void addNounsToDictionary ( List < String > words ) { OpenKoreanTextProcessor . addNounsToDictionary ( JavaConverters . asScalaBufferConverter ( words ) . asScala ( ) ) ; }

Add user-defined words to the noun dictionary. Spaced words are ignored.

@param words List of user nouns.

Add user - defined words to the noun dictionary . Spaced words are ignored .


public static void removeWordFromDictionary(KoreanPosJava pos, List<String> words) {
    OpenKoreanTextProcessor.removeWordsFromDictionary(KoreanPos.withName(pos.toString()), JavaConverters.asScalaBufferConverter(words).asScala());
  }

public static void removeWordFromDictionary ( KoreanPosJava pos , List < String > words ) { OpenKoreanTextProcessor . removeWordsFromDictionary ( KoreanPos . withName ( pos . toString ( ) ) , JavaConverters . asScalaBufferConverter ( words ) . asScala ( ) ) ; }

Remove user-defined word List from the dictionary for the specified KoreanPos.

@param pos   KoreanPos of words to add.
@param words Sequence of words to add.

Remove user - defined word List from the dictionary for the specified KoreanPos .


public static List<String> tokensToJavaStringList(Seq<KoreanToken> tokens, boolean keepSpace) {
    Iterator<KoreanToken> tokenized = tokens.iterator();
    List<String> output = new LinkedList<>();
    while (tokenized.hasNext()) {
      final KoreanToken token = tokenized.next();

      if (keepSpace || token.pos() != KoreanPos.Space()) {
        output.add(token.text());
      }
    }
    return output;
  }

public static List < String > tokensToJavaStringList ( Seq < KoreanToken > tokens , boolean keepSpace ) { Iterator < KoreanToken > tokenized = tokens . iterator ( ) ; List < String > output = new LinkedList <> ( ) ; while ( tokenized . hasNext ( ) ) { final KoreanToken token = tokenized . next ( ) ; if ( keepSpace || token . pos ( ) != KoreanPos . Space ( ) ) { output . add ( token . text ( ) ) ; } } return output ; }

Tokenize with the builder options into a String Iterable.

@param tokens Korean tokens (output of tokenize(CharSequence text)).
@return List of token strings.

Tokenize with the builder options into a String Iterable .


public static List<KoreanPhraseExtractor.KoreanPhrase> extractPhrases(Seq<KoreanToken> tokens, boolean filterSpam, boolean includeHashtags) {
    Seq<KoreanPhraseExtractor.KoreanPhrase> seq = OpenKoreanTextProcessor.extractPhrases(tokens, filterSpam, includeHashtags);
    return toJavaList(seq);
  }

public static List < KoreanPhraseExtractor . KoreanPhrase > extractPhrases ( Seq < KoreanToken > tokens , boolean filterSpam , boolean includeHashtags ) { Seq < KoreanPhraseExtractor . KoreanPhrase > seq = OpenKoreanTextProcessor . extractPhrases ( tokens , filterSpam , includeHashtags ) ; return toJavaList ( seq ) ; }

Extract phrases from Korean input text

@param tokens Korean tokens (output of tokenize(CharSequence text)).
@return List of phrase CharSequences.


public static String detokenize(List<String> tokens) {
    return OpenKoreanTextProcessor.detokenize(JavaConverters.asScalaBufferConverter(tokens).asScala());
  }

public static String detokenize ( List < String > tokens ) { return OpenKoreanTextProcessor . detokenize ( JavaConverters . asScalaBufferConverter ( tokens ) . asScala ( ) ) ; }

Detokenize the input list of words.

@param tokens List of words.
@return Detokenized string.


public static ByteBuffer fetchFrom(ByteBuffer buf, ReadableByteChannel ch, int size) throws IOException {
        ByteBuffer result = buf.duplicate();
        result.limit(size);
        NIOUtils.readFromChannel(ch, result);
        result.flip();
        return result;
    }

public static ByteBuffer fetchFrom ( ByteBuffer buf , ReadableByteChannel ch , int size ) throws IOException { ByteBuffer result = buf . duplicate ( ) ; result . limit ( size ) ; NIOUtils . readFromChannel ( ch , result ) ; result . flip ( ) ; return result ; }

Reads size amount of bytes from ch into a new ByteBuffer allocated from a
buffer buf

@param buf
@param ch
@param size
@return
@throws IOException


public static ByteBuffer joinNALUnits(List<ByteBuffer> nalUnits) {
        int size = 0;
        for (ByteBuffer nal : nalUnits) {
            size += 4 + nal.remaining();
        }
        ByteBuffer allocate = ByteBuffer.allocate(size);
        joinNALUnitsToBuffer(nalUnits, allocate);
        return allocate;
    }

public static ByteBuffer joinNALUnits ( List < ByteBuffer > nalUnits ) { int size = 0 ; for ( ByteBuffer nal : nalUnits ) { size += 4 + nal . remaining ( ) ; } ByteBuffer allocate = ByteBuffer . allocate ( size ) ; joinNALUnitsToBuffer ( nalUnits , allocate ) ; return allocate ; }

Joins buffers containing individual NAL units into a single AnnexB
delimited buffer. Each NAL unit will be separated with 00 00 00 01
markers. Allocates a new byte buffer and writes data into it.

@param nalUnits
@param out

Joins buffers containing individual NAL units into a single AnnexB delimited buffer . Each NAL unit will be separated with 00 00 00 01 markers . Allocates a new byte buffer and writes data into it .


public static void joinNALUnitsToBuffer(List<ByteBuffer> nalUnits, ByteBuffer out) {
        for (ByteBuffer nal : nalUnits) {
            out.putInt(1);
            out.put(nal.duplicate());
        }
    }

public static void joinNALUnitsToBuffer ( List < ByteBuffer > nalUnits , ByteBuffer out ) { for ( ByteBuffer nal : nalUnits ) { out . putInt ( 1 ) ; out . put ( nal . duplicate ( ) ) ; } }

Joins buffers containing individual NAL units into a single AnnexB
delimited buffer. Each NAL unit will be separated with 00 00 00 01
markers.

@param nalUnits
@param out

Joins buffers containing individual NAL units into a single AnnexB delimited buffer . Each NAL unit will be separated with 00 00 00 01 markers .


public static Profile forInt(int i) {
		Profile p;
		if(i<=0||i>ALL.length) p = UNKNOWN;
		else p = ALL[i-1];
		return p;
	}

public static Profile forInt ( int i ) { Profile p ; if ( i <= 0 || i > ALL . length ) p = UNKNOWN ; else p = ALL [ i - 1 ] ; return p ; }

Returns a profile instance for the given index. If the index is not
between 1 and 23 inclusive, UNKNOWN is returned.
@return a profile with the given index

Returns a profile instance for the given index . If the index is not between 1 and 23 inclusive UNKNOWN is returned .


public static void normalizeAndGenerateFixedPrecision(double[] taps, int precBits, short[] out) {
        double sum = 0;
        for (int i = 0; i < taps.length; i++) {
            sum += taps[i];
        }
        int sumFix = 0;
        int precNum = 1 << precBits;
        for (int i = 0; i < taps.length; i++) {
            double d = (taps[i] * precNum) / sum + precNum;
            int s = (int) d;
            taps[i] = d - s;
            out[i] = (short) (s - precNum);
            sumFix += out[i];
        }
        long tapsTaken = 0;
        while (sumFix < precNum) {
            int maxI = -1;
            for (int i = 0; i < taps.length; i++) {
                if ((tapsTaken & (1 << i)) == 0 && (maxI == -1 || taps[i] > taps[maxI]))
                    maxI = i;
            }
            out[maxI]++;
            sumFix++;
            tapsTaken |= (1 << maxI);
        }

        for (int i = 0; i < taps.length; i++) {
            taps[i] += out[i];
            if ((tapsTaken & (1 << i)) != 0)
                taps[i] -= 1;
        }
    }

public static void normalizeAndGenerateFixedPrecision ( double [ ] taps , int precBits , short [ ] out ) { double sum = 0 ; for ( int i = 0 ; i < taps . length ; i ++ ) { sum += taps [ i ] ; } int sumFix = 0 ; int precNum = 1 << precBits ; for ( int i = 0 ; i < taps . length ; i ++ ) { double d = ( taps [ i ] * precNum ) / sum + precNum ; int s = ( int ) d ; taps [ i ] = d - s ; out [ i ] = ( short ) ( s - precNum ) ; sumFix += out [ i ] ; } long tapsTaken = 0 ; while ( sumFix < precNum ) { int maxI = - 1 ; for ( int i = 0 ; i < taps . length ; i ++ ) { if ( ( tapsTaken & ( 1 << i ) ) == 0 && ( maxI == - 1 || taps [ i ] > taps [ maxI ] ) ) maxI = i ; } out [ maxI ] ++ ; sumFix ++ ; tapsTaken |= ( 1 << maxI ) ; } for ( int i = 0 ; i < taps . length ; i ++ ) { taps [ i ] += out [ i ] ; if ( ( tapsTaken & ( 1 << i ) ) != 0 ) taps [ i ] -= 1 ; } }

Converts floating point taps to fixed precision taps.

@param taps
The 64 bit double representation
@param precBits
Precision bits
@param out
Taps converted to fixed precision

Converts floating point taps to fixed precision taps .


public final State readToNextMarkerPartial(ByteBuffer out) throws IOException {
        if (done)
            return State.STOP;
        int skipOneMarker = curMarker >= 0x100 && curMarker <= 0x1ff ? 1 : 0;
        int written = out.position();
        do {
            while (buf.hasRemaining()) {
                if (curMarker >= 0x100 && curMarker <= 0x1ff) {
                    if (skipOneMarker == 0) {
                        return State.DONE;
                    }
                    --skipOneMarker;
                }
                if (!out.hasRemaining())
                    return State.MORE_DATA;
                out.put((byte) (curMarker >>> 24));
                curMarker = (curMarker << 8) | (buf.get() & 0xff);
            }
            buf = NIOUtils.fetchFromChannel(channel, fetchSize);
            pos += buf.remaining();
        } while (buf.hasRemaining());

        written = out.position() - written;
        if (written > 0 && curMarker >= 0x100 && curMarker <= 0x1ff)
            return State.DONE;

        for (; bytesInMarker > 0 && out.hasRemaining();) {
            out.put((byte) (curMarker >>> 24));
            curMarker = (curMarker << 8);
            --bytesInMarker;
            if (curMarker >= 0x100 && curMarker <= 0x1ff)
                return State.DONE;
        }

        if (bytesInMarker == 0) {
            done = true;
            return State.STOP;
        } else {
            return State.MORE_DATA;
        }
    }

public final State readToNextMarkerPartial ( ByteBuffer out ) throws IOException { if ( done ) return State . STOP ; int skipOneMarker = curMarker >= 0x100 && curMarker <= 0x1ff ? 1 : 0 ; int written = out . position ( ) ; do { while ( buf . hasRemaining ( ) ) { if ( curMarker >= 0x100 && curMarker <= 0x1ff ) { if ( skipOneMarker == 0 ) { return State . DONE ; } -- skipOneMarker ; } if ( ! out . hasRemaining ( ) ) return State . MORE_DATA ; out . put ( ( byte ) ( curMarker >>> 24 ) ) ; curMarker = ( curMarker << 8 ) | ( buf . get ( ) & 0xff ) ; } buf = NIOUtils . fetchFromChannel ( channel , fetchSize ) ; pos += buf . remaining ( ) ; } while ( buf . hasRemaining ( ) ) ; written = out . position ( ) - written ; if ( written > 0 && curMarker >= 0x100 && curMarker <= 0x1ff ) return State . DONE ; for ( ; bytesInMarker > 0 && out . hasRemaining ( ) ; ) { out . put ( ( byte ) ( curMarker >>> 24 ) ) ; curMarker = ( curMarker << 8 ) ; -- bytesInMarker ; if ( curMarker >= 0x100 && curMarker <= 0x1ff ) return State . DONE ; } if ( bytesInMarker == 0 ) { done = true ; return State . STOP ; } else { return State . MORE_DATA ; } }

Reads one full segment till the next marker. Will read as much data as
the provided buffer fits, if the provided buffer doesn't fit all data
will return MORE_DATA.

@param out
@return
@throws IOException

Reads one full segment till the next marker . Will read as much data as the provided buffer fits if the provided buffer doesn t fit all data will return MORE_DATA .


public ByteBuffer readToNextMarkerNewBuffer() throws IOException {
        if (done)
            return null;
        List<ByteBuffer> buffers = new ArrayList<ByteBuffer>();
        readToNextMarkerBuffers(buffers);

        return NIOUtils.combineBuffers(buffers);
    }

public ByteBuffer readToNextMarkerNewBuffer ( ) throws IOException { if ( done ) return null ; List < ByteBuffer > buffers = new ArrayList < ByteBuffer > ( ) ; readToNextMarkerBuffers ( buffers ) ; return NIOUtils . combineBuffers ( buffers ) ; }

Reads one full segment till the next marker. Will allocate the necessary
buffer to hold the full segment. Internally uses a growing collection of
smaller buffers since the segment size is intitially unkwnown.

@return
@throws IOException

Reads one full segment till the next marker . Will allocate the necessary buffer to hold the full segment . Internally uses a growing collection of smaller buffers since the segment size is intitially unkwnown .


public int getMaxAvailableFrame() {
        if (maxAvailableFrame == -1) {

            int firstPoint = 0;
            for (int i = MAX_MAX; i > 0; i /= 2) {
                if (new File(String.format(namePattern, i)).exists()) {
                    firstPoint = i;
                    break;
                }
            }
            int pos = firstPoint;
            for (int interv = firstPoint / 2; interv > 1; interv /= 2) {
                if (new File(String.format(namePattern, pos + interv)).exists()) {
                    pos += interv;
                }
            }
            maxAvailableFrame = pos;
            Logger.info("Max frame found: " + maxAvailableFrame);
        }
        return Math.min(maxAvailableFrame, maxFrames);
    }

public
int
getMaxAvailableFrame
(
)
{
if
(
maxAvailableFrame
==
1
)
{
int
firstPoint
=
0
;
for
(
int
i
=
MAX_MAX
;
i
>
0
;
i
/=
2
)
{
if
(
new
File
(
String
.
format
(
namePattern
,
i
)
)
.
exists
(
)
)
{
firstPoint
=
i
;
break
;
}
}
int
pos
=
firstPoint
;
for
(
int
interv
=
firstPoint
/
2
;
interv
>
1
;
interv
/=
2
)
{
if
(
new
File
(
String
.
format
(
namePattern
,
pos
+
interv
)
)
.
exists
(
)
)
{
pos
+=
interv
;
}
}
maxAvailableFrame
=
pos
;
Logger
.
info
(
"Max frame found: "
+
maxAvailableFrame
)
;
}
return
Math
.
min
(
maxAvailableFrame
,
maxFrames
)
;
}

Finds maximum frame of a sequence by bisecting the range.

Performs at max at max 48 Stat calls ( 2*log2(MAX_MAX) ).

@return

Finds maximum frame of a sequence by bisecting the range .


public boolean modify(File file, MP4Edit edit) throws IOException {
        SeekableByteChannel fi = null;
        try {
            fi = NIOUtils.rwChannel(file);

            List<Tuple._2<Atom, ByteBuffer>> fragments = doTheFix(fi, edit);
            if (fragments == null)
                return false;

            // If everything is clean, only then actually writing stuff to the
            // file
            for (Tuple._2<Atom, ByteBuffer> fragment : fragments) {
                replaceBox(fi, fragment.v0, fragment.v1);
            }

            return true;
        } finally {
            NIOUtils.closeQuietly(fi);
        }
    }

Tries to modify movie header in place according to what's implemented in
the edit, the file gets pysically modified if the operation is
successful. No temporary file is created.

@param file
A file to be modified
@param edit
An edit to be carried out on a movie header
@return Whether or not edit was successful, i.e. was there enough place
to put the new header
@throws IOException
@throws Exception

Tries to modify movie header in place according to what s implemented in the edit the file gets pysically modified if the operation is successful . No temporary file is created .


public boolean copy(File src, File dst, MP4Edit edit) throws IOException {
        SeekableByteChannel fi = null;
        SeekableByteChannel fo = null;
        try {
            fi = NIOUtils.readableChannel(src);
            fo = NIOUtils.writableChannel(dst);

            List<Tuple._2<Atom, ByteBuffer>> fragments = doTheFix(fi, edit);
            if (fragments == null)
                return false;

            List<_2<Long, ByteBuffer>> fragOffsets = Tuple._2map0(fragments, new Tuple.Mapper<Atom, Long>() {
                public Long map(Atom t) {
                    return t.getOffset();
                }
            });

            // If everything is clean, only then actually start writing file
            Map<Long, ByteBuffer> rewrite = Tuple.asMap(fragOffsets);
            for (Atom atom : MP4Util.getRootAtoms(fi)) {
                ByteBuffer byteBuffer = rewrite.get(atom.getOffset());
                if (byteBuffer != null)
                    fo.write(byteBuffer);
                else
                    atom.copy(fi, fo);
            }

            return true;
        } finally {
            NIOUtils.closeQuietly(fi);
            NIOUtils.closeQuietly(fo);
        }
    }

Tries to modify movie header in place according to what's implemented in
the edit. Copies modified contents to a new file.

Note: The header is still edited in-place, so the new file will have
all-the-same sample offsets.

Note: Still subject to the same limitations as 'modify', i.e. the new
header must 'fit' into an old place.

This method is useful when you can't write to the original file, for ex.
you don't have permission.

@param src
An original file
@param dst
A file to store the modified copy
@param edit
An edit logic to apply
@return
@throws IOException

Tries to modify movie header in place according to what s implemented in the edit . Copies modified contents to a new file .


public static long getEditedDuration(TrakBox track) {
        List<Edit> edits = track.getEdits();
        if (edits == null)
            return track.getDuration();

        long duration = 0;
        for (Edit edit : edits) {
            duration += edit.getDuration();
        }
        return duration;
    }

public static long getEditedDuration ( TrakBox track ) { List < Edit > edits = track . getEdits ( ) ; if ( edits == null ) return track . getDuration ( ) ; long duration = 0 ; for ( Edit edit : edits ) { duration += edit . getDuration ( ) ; } return duration ; }

Calculates track duration considering edits

@param track
@return


public static long frameToTimevalue(TrakBox trak, int frameNumber) {
        TimeToSampleBox stts = NodeBox.findFirstPath(trak, TimeToSampleBox.class, Box.path("mdia.minf.stbl.stts"));
        TimeToSampleEntry[] timeToSamples = stts.getEntries();
        long pts = 0;
        int sttsInd = 0, sttsSubInd = frameNumber;
        while (sttsSubInd >= timeToSamples[sttsInd].getSampleCount()) {
            sttsSubInd -= timeToSamples[sttsInd].getSampleCount();
            pts += timeToSamples[sttsInd].getSampleCount() * timeToSamples[sttsInd].getSampleDuration();
            sttsInd++;
        }

        return pts + timeToSamples[sttsInd].getSampleDuration() * sttsSubInd;
    }

public static long frameToTimevalue ( TrakBox trak , int frameNumber ) { TimeToSampleBox stts = NodeBox . findFirstPath ( trak , TimeToSampleBox . class , Box . path ( "mdia.minf.stbl.stts" ) ) ; TimeToSampleEntry [ ] timeToSamples = stts . getEntries ( ) ; long pts = 0 ; int sttsInd = 0 , sttsSubInd = frameNumber ; while ( sttsSubInd >= timeToSamples [ sttsInd ] . getSampleCount ( ) ) { sttsSubInd -= timeToSamples [ sttsInd ] . getSampleCount ( ) ; pts += timeToSamples [ sttsInd ] . getSampleCount ( ) * timeToSamples [ sttsInd ] . getSampleDuration ( ) ; sttsInd ++ ; } return pts + timeToSamples [ sttsInd ] . getSampleDuration ( ) * sttsSubInd ; }

Finds timevalue of a frame number

might be an expensive operation sinse it traverses compressed time to
sample table

@param frameNumber
@return


public static int timevalueToFrame(TrakBox trak, long tv) {
        TimeToSampleEntry[] tts = NodeBox.findFirstPath(trak, TimeToSampleBox.class, Box.path("mdia.minf.stbl.stts")).getEntries();
        int frame = 0;
        for (int i = 0; tv > 0 && i < tts.length; i++) {
            long rem = tv / tts[i].getSampleDuration();
            tv -= tts[i].getSampleCount() * tts[i].getSampleDuration();
            frame += tv > 0 ? tts[i].getSampleCount() : rem;
        }

        return frame;
    }

public static int timevalueToFrame ( TrakBox trak , long tv ) { TimeToSampleEntry [ ] tts = NodeBox . findFirstPath ( trak , TimeToSampleBox . class , Box . path ( "mdia.minf.stbl.stts" ) ) . getEntries ( ) ; int frame = 0 ; for ( int i = 0 ; tv > 0 && i < tts . length ; i ++ ) { long rem = tv / tts [ i ] . getSampleDuration ( ) ; tv -= tts [ i ] . getSampleCount ( ) * tts [ i ] . getSampleDuration ( ) ; frame += tv > 0 ? tts [ i ] . getSampleCount ( ) : rem ; } return frame ; }

Finds frame by timevalue

@param tv
@return


public static long mediaToEdited(TrakBox trak, long mediaTv, int movieTimescale) {
        if (trak.getEdits() == null)
            return mediaTv;
        long accum = 0;
        for (Edit edit : trak.getEdits()) {
            if (mediaTv < edit.getMediaTime())
                return accum;
            long duration = trak.rescale(edit.getDuration(), movieTimescale);
            if (edit.getMediaTime() != -1
                    && (mediaTv >= edit.getMediaTime() && mediaTv < edit.getMediaTime() + duration)) {
                accum += mediaTv - edit.getMediaTime();
                break;
            }
            accum += duration;
        }

        return accum;
    }

public static long mediaToEdited ( TrakBox trak , long mediaTv , int movieTimescale ) { if ( trak . getEdits ( ) == null ) return mediaTv ; long accum = 0 ; for ( Edit edit : trak . getEdits ( ) ) { if ( mediaTv < edit . getMediaTime ( ) ) return accum ; long duration = trak . rescale ( edit . getDuration ( ) , movieTimescale ) ; if ( edit . getMediaTime ( ) != - 1 && ( mediaTv >= edit . getMediaTime ( ) && mediaTv < edit . getMediaTime ( ) + duration ) ) { accum += mediaTv - edit . getMediaTime ( ) ; break ; } accum += duration ; } return accum ; }

Converts media timevalue to edited timevalue

@param trak
@param mediaTv
@param movieTimescale
@return


public static long editedToMedia(TrakBox trak, long editedTv, int movieTimescale) {
        if (trak.getEdits() == null)
            return editedTv;
        long accum = 0;
        for (Edit edit : trak.getEdits()) {
            long duration = trak.rescale(edit.getDuration(), movieTimescale);

            if (accum + duration > editedTv) {
                return edit.getMediaTime() + editedTv - accum;
            }

            accum += duration;
        }

        return accum;
    }

public static long editedToMedia ( TrakBox trak , long editedTv , int movieTimescale ) { if ( trak . getEdits ( ) == null ) return editedTv ; long accum = 0 ; for ( Edit edit : trak . getEdits ( ) ) { long duration = trak . rescale ( edit . getDuration ( ) , movieTimescale ) ; if ( accum + duration > editedTv ) { return edit . getMediaTime ( ) + editedTv - accum ; } accum += duration ; } return accum ; }

Converts edited timevalue to media timevalue

@param trak
@param mediaTv
@param movieTimescale
@return


public static int qtPlayerFrameNo(MovieBox movie, int mediaFrameNo) {
        TrakBox videoTrack = movie.getVideoTrack();

        long editedTv = mediaToEdited(videoTrack, frameToTimevalue(videoTrack, mediaFrameNo), movie.getTimescale());

        return tv2QTFrameNo(movie, editedTv);
    }

public static int qtPlayerFrameNo ( MovieBox movie , int mediaFrameNo ) { TrakBox videoTrack = movie . getVideoTrack ( ) ; long editedTv = mediaToEdited ( videoTrack , frameToTimevalue ( videoTrack , mediaFrameNo ) , movie . getTimescale ( ) ) ; return tv2QTFrameNo ( movie , editedTv ) ; }

Calculates frame number as it shows in quicktime player

@param movie
@param mediaFrameNo
@return


public static String qtPlayerTime(MovieBox movie, int mediaFrameNo) {
        TrakBox videoTrack = movie.getVideoTrack();
        long editedTv = mediaToEdited(videoTrack, frameToTimevalue(videoTrack, mediaFrameNo), movie.getTimescale());

        int sec = (int) (editedTv / videoTrack.getTimescale());
        return String.format("%02d", sec / 3600) + "_" + String.format("%02d", (sec % 3600) / 60) + "_"
                + String.format("%02d", sec % 60);
    }

public static String qtPlayerTime ( MovieBox movie , int mediaFrameNo ) { TrakBox videoTrack = movie . getVideoTrack ( ) ; long editedTv = mediaToEdited ( videoTrack , frameToTimevalue ( videoTrack , mediaFrameNo ) , movie . getTimescale ( ) ) ; int sec = ( int ) ( editedTv / videoTrack . getTimescale ( ) ) ; return String . format ( "%02d" , sec / 3600 ) + "_" + String . format ( "%02d" , ( sec % 3600 ) / 60 ) + "_" + String . format ( "%02d" , sec % 60 ) ; }

Calculates and formats standard time as in Quicktime player

@param movie
@param mediaFrameNo
@return


public static int timevalueToTimecodeFrame(TrakBox timecodeTrack, RationalLarge tv, int movieTimescale) {
        TimecodeSampleEntry se = (TimecodeSampleEntry) timecodeTrack.getSampleEntries()[0];
        return (int) ((2 * tv.multiplyS(se.getTimescale()) / se.getFrameDuration()) + 1) / 2;
    }

public static int timevalueToTimecodeFrame ( TrakBox timecodeTrack , RationalLarge tv , int movieTimescale ) { TimecodeSampleEntry se = ( TimecodeSampleEntry ) timecodeTrack . getSampleEntries ( ) [ 0 ] ; return ( int ) ( ( 2 * tv . multiplyS ( se . getTimescale ( ) ) / se . getFrameDuration ( ) ) + 1 ) / 2 ; }

Converts timevalue to frame number based on timecode track

@param timecodeTrack
@param tv
@return


public static String formatTimecode(TrakBox timecodeTrack, int counter) {
        TimecodeSampleEntry tmcd = NodeBox.findFirstPath(timecodeTrack, TimecodeSampleEntry.class, Box.path("mdia.minf.stbl.stsd.tmcd"));
        byte nf = tmcd.getNumFrames();

        String tc = String.format("%02d", counter % nf);
        counter /= nf;
        tc = String.format("%02d", counter % 60) + ":" + tc;
        counter /= 60;
        tc = String.format("%02d", counter % 60) + ":" + tc;
        counter /= 60;
        tc = String.format("%02d", counter) + ":" + tc;

        return tc;
    }

public static String formatTimecode ( TrakBox timecodeTrack , int counter ) { TimecodeSampleEntry tmcd = NodeBox . findFirstPath ( timecodeTrack , TimecodeSampleEntry . class , Box . path ( "mdia.minf.stbl.stsd.tmcd" ) ) ; byte nf = tmcd . getNumFrames ( ) ; String tc = String . format ( "%02d" , counter % nf ) ; counter /= nf ; tc = String . format ( "%02d" , counter % 60 ) + ":" + tc ; counter /= 60 ; tc = String . format ( "%02d" , counter % 60 ) + ":" + tc ; counter /= 60 ; tc = String . format ( "%02d" , counter ) + ":" + tc ; return tc ; }

Formats tape timecode based on frame counter

@param timecodeTrack
@param counter
@return


Creates packed 4bit list with 7 values in it

@return


public static int set(int list, int val, int n) {
        int cnt = (list >> 28) & 0xf;
        int newc = n + 1;
        cnt = newc > cnt ? newc : cnt;
        return (list & CLEAR_MASK[n]) | ((val & 0xff) << (n << 2)) | (cnt << 28);
    }

public static int set ( int list , int val , int n ) { int cnt = ( list >> 28 ) & 0xf ; int newc = n + 1 ; cnt = newc > cnt ? newc : cnt ; return ( list & CLEAR_MASK [ n ] ) | ( ( val & 0xff ) << ( n << 2 ) ) | ( cnt << 28 ) ; }

Sets a 4 bit value into the list

@param list
@param val
@param n
@return


public boolean matches(ColorSpace inputColor) {
        if (inputColor == this)
            return true;
        if (inputColor == ANY || this == ANY)
            return true;
        if ((inputColor == ANY_INTERLEAVED || this == ANY_INTERLEAVED || inputColor == ANY_PLANAR || this == ANY_PLANAR)
                && inputColor.planar == this.planar)
            return true;
        return false;
    }

public boolean matches ( ColorSpace inputColor ) { if ( inputColor == this ) return true ; if ( inputColor == ANY || this == ANY ) return true ; if ( ( inputColor == ANY_INTERLEAVED || this == ANY_INTERLEAVED || inputColor == ANY_PLANAR || this == ANY_PLANAR ) && inputColor . planar == this . planar ) return true ; return false ; }

Determines if two colors match. Aside from simply comparing the objects
this function also takes into account lables ANY, ANY_INTERLEAVED, ANY
PLANAR.

@param inputColor
@return True if the color is the same or matches the label.

Determines if two colors match . Aside from simply comparing the objects this function also takes into account lables ANY ANY_INTERLEAVED ANY PLANAR .


public Size compSize(Size size, int comp) {
        if (compWidth[comp] == 0 && compHeight[comp] == 0)
            return size;
        return new Size(size.getWidth() >> compWidth[comp], size.getHeight() >> compHeight[comp]);
    }

public Size compSize ( Size size , int comp ) { if ( compWidth [ comp ] == 0 && compHeight [ comp ] == 0 ) return size ; return new Size ( size . getWidth ( ) >> compWidth [ comp ] , size . getHeight ( ) >> compHeight [ comp ] ) ; }

Calculates the component size based on the fullt size and color subsampling of the given component index.
@param size
@return Component size

Calculates the component size based on the fullt size and color subsampling of the given component index .


public static MP4Demuxer createRawMP4Demuxer(SeekableByteChannel input) throws IOException {
        return new MP4Demuxer(input) {
            @Override
            protected AbstractMP4DemuxerTrack newTrack(TrakBox trak) {
                return new MP4DemuxerTrack(movie, trak, this.input);
            }
        };
    }

public static MP4Demuxer createRawMP4Demuxer ( SeekableByteChannel input ) throws IOException { return new MP4Demuxer ( input ) { @ Override protected AbstractMP4DemuxerTrack newTrack ( TrakBox trak ) { return new MP4DemuxerTrack ( movie , trak , this . input ) ; } } ; }


protected int readCache(boolean peek) throws AACException {
		int i;
		if(pos>buffer.length-WORD_BYTES) throw AACException.endOfStream();
		else i = ((buffer[pos]&BYTE_MASK)<<24)
					|((buffer[pos+1]&BYTE_MASK)<<16)
					|((buffer[pos+2]&BYTE_MASK)<<8)
					|(buffer[pos+3]&BYTE_MASK);
		if(!peek) pos += WORD_BYTES;
		return i;
	}

protected int readCache ( boolean peek ) throws AACException { int i ; if ( pos > buffer . length - WORD_BYTES ) throw AACException . endOfStream ( ) ; else i = ( ( buffer [ pos ] & BYTE_MASK ) << 24 ) | ( ( buffer [ pos + 1 ] & BYTE_MASK ) << 16 ) | ( ( buffer [ pos + 2 ] & BYTE_MASK ) << 8 ) | ( buffer [ pos + 3 ] & BYTE_MASK ) ; if ( ! peek ) pos += WORD_BYTES ; return i ; }

Reads the next four bytes.
@param peek if true, the stream pointer will not be increased


public static WavHeader createWavHeader(AudioFormat format, int samples) {
        WavHeader w = new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short) 1, (short) format.getChannels(), format.getSampleRate(),
                format.getSampleRate() * format.getChannels() * (format.getSampleSizeInBits() >> 3),
                (short) (format.getChannels() * (format.getSampleSizeInBits() >> 3)),
                (short) format.getSampleSizeInBits()), 44, calcDataSize(format.getChannels(),
                format.getSampleSizeInBits() >> 3, samples));
        return w;
    }

public static WavHeader createWavHeader ( AudioFormat format , int samples ) { WavHeader w = new WavHeader ( "RIFF" , 40 , "WAVE" , new FmtChunk ( ( short ) 1 , ( short ) format . getChannels ( ) , format . getSampleRate ( ) , format . getSampleRate ( ) * format . getChannels ( ) * ( format . getSampleSizeInBits ( ) >> 3 ) , ( short ) ( format . getChannels ( ) * ( format . getSampleSizeInBits ( ) >> 3 ) ) , ( short ) format . getSampleSizeInBits ( ) ) , 44 , calcDataSize ( format . getChannels ( ) , format . getSampleSizeInBits ( ) >> 3 , samples ) ) ; return w ; }

Creates wav header for the specified audio format

@param format
@param samples


public static WavHeader multiChannelWav(WavHeader[] headers) {
        WavHeader w = emptyWavHeader();
        int totalSize = 0;
        for (int i = 0; i < headers.length; i++) {
            WavHeader wavHeader = headers[i];
            totalSize += wavHeader.dataSize;
        }
        w.dataSize = totalSize;
        FmtChunk fmt = headers[0].fmt;
        int bitsPerSample = fmt.bitsPerSample;
        int bytesPerSample = bitsPerSample / 8;
        int sampleRate = (int) fmt.sampleRate;
        w.fmt.bitsPerSample = (short) bitsPerSample;
        w.fmt.blockAlign = (short) (headers.length * bytesPerSample);
        w.fmt.byteRate = headers.length * bytesPerSample * sampleRate;
        w.fmt.numChannels = (short) headers.length;
        w.fmt.sampleRate = sampleRate;
        return w;
    }

public static WavHeader multiChannelWav ( WavHeader [ ] headers ) { WavHeader w = emptyWavHeader ( ) ; int totalSize = 0 ; for ( int i = 0 ; i < headers . length ; i ++ ) { WavHeader wavHeader = headers [ i ] ; totalSize += wavHeader . dataSize ; } w . dataSize = totalSize ; FmtChunk fmt = headers [ 0 ] . fmt ; int bitsPerSample = fmt . bitsPerSample ; int bytesPerSample = bitsPerSample / 8 ; int sampleRate = ( int ) fmt . sampleRate ; w . fmt . bitsPerSample = ( short ) bitsPerSample ; w . fmt . blockAlign = ( short ) ( headers . length * bytesPerSample ) ; w . fmt . byteRate = headers . length * bytesPerSample * sampleRate ; w . fmt . numChannels = ( short ) headers . length ; w . fmt . sampleRate = sampleRate ; return w ; }

Takes single channel wavs as input produces multi channel wav


public static AACDecoderConfig parseMP4DecoderSpecificInfo(byte[] data) throws AACException {
		final IBitStream _in = BitStream.createBitStream(data);
		final AACDecoderConfig config = new AACDecoderConfig();

		try {
			config.profile = readProfile(_in);

			int sf = _in.readBits(4);
			if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(_in.readBits(24));
			else config.sampleFrequency = SampleFrequency.forInt(sf);
			config.channelConfiguration = ChannelConfiguration.forInt(_in.readBits(4));

			Profile cp = config.profile;
			if (AAC_SBR == cp) {
                config.extProfile = cp;
                config.sbrPresent = true;
                sf = _in.readBits(4);
                //TODO: 24 bits already read; read again?
                //if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(_in.readBits(24));
                //if sample frequencies are the same: downsample SBR
                config.downSampledSBR = config.sampleFrequency.getIndex()==sf;
                config.sampleFrequency = SampleFrequency.forInt(sf);
                config.profile = readProfile(_in);
			} else if (AAC_MAIN == cp || AAC_LC ==  cp || AAC_SSR == cp || AAC_LTP == cp || ER_AAC_LC == cp || ER_AAC_LTP == cp || ER_AAC_LD == cp ) {
                //ga-specific info:
                config.frameLengthFlag = _in.readBool();
                if(config.frameLengthFlag) throw new AACException("config uses 960-sample frames, not yet supported"); //TODO: are 960-frames working yet?
                config.dependsOnCoreCoder = _in.readBool();
                if(config.dependsOnCoreCoder) config.coreCoderDelay = _in.readBits(14);
                else config.coreCoderDelay = 0;
                config.extensionFlag = _in.readBool();

                if(config.extensionFlag) {
                    if(cp.isErrorResilientProfile()) {
                        config.sectionDataResilience = _in.readBool();
                        config.scalefactorResilience = _in.readBool();
                        config.spectralDataResilience = _in.readBool();
                    }
                    //extensionFlag3
                    _in.skipBit();
                }

                if(config.channelConfiguration==ChannelConfiguration.CHANNEL_CONFIG_NONE) {
                    //TODO: is this working correct? -> ISO 14496-3 part 1: 1.A.4.3
                    _in.skipBits(3); //PCE
                    PCE pce = new PCE();
                    pce.decode(_in);
                    config.profile = pce.getProfile();
                    config.sampleFrequency = pce.getSampleFrequency();
                    config.channelConfiguration = ChannelConfiguration.forInt(pce.getChannelCount());
                }

                if(_in.getBitsLeft()>10) readSyncExtension(_in, config);
			} else {
                throw new AACException("profile not supported: "+cp.getIndex());
			}
			return config;
		}
		finally {
			_in.destroy();
		}
	}

Parses the input arrays as a DecoderSpecificInfo, as used in MP4
containers.

@return a AACDecoderConfig

Parses the input arrays as a DecoderSpecificInfo as used in MP4 containers .


public void encode(int symbol, Context cm) throws IOException {

        int rangeLps = MQConst.pLps[cm.getState()];
        if (symbol == cm.getMps()) {
            range -= rangeLps;
            offset += rangeLps;
            if (range < 0x8000) {
                while (range < 0x8000)
                    renormalize();
                cm.setState(MQConst.transitMPS[cm.getState()]);
            }
        } else {
            range = rangeLps;
            while (range < 0x8000)
                renormalize();

            if (MQConst.mpsSwitch[cm.getState()] != 0)
                cm.setMps(1 - cm.getMps());
            cm.setState(MQConst.transitLPS[cm.getState()]);
        }
    }

public void encode ( int symbol , Context cm ) throws IOException { int rangeLps = MQConst . pLps [ cm . getState ( ) ] ; if ( symbol == cm . getMps ( ) ) { range -= rangeLps ; offset += rangeLps ; if ( range < 0x8000 ) { while ( range < 0x8000 ) renormalize ( ) ; cm . setState ( MQConst . transitMPS [ cm . getState ( ) ] ) ; } } else { range = rangeLps ; while ( range < 0x8000 ) renormalize ( ) ; if ( MQConst . mpsSwitch [ cm . getState ( ) ] != 0 ) cm . setMps ( 1 - cm . getMps ( ) ) ; cm . setState ( MQConst . transitLPS [ cm . getState ( ) ] ) ; } }

Encodes one symbol either 0 or 1

@param symbol
@throws IOException


private static void readDecoderPicMarking(NALUnit nalUnit, SliceHeader sh, BitReader _in) {
        if (nalUnit.type == NALUnitType.IDR_SLICE) {
            boolean noOutputOfPriorPicsFlag = readBool(_in, "SH: no_output_of_prior_pics_flag");
            boolean longTermReferenceFlag = readBool(_in, "SH: long_term_reference_flag");
            sh.refPicMarkingIDR = new RefPicMarkingIDR(noOutputOfPriorPicsFlag, longTermReferenceFlag);
        } else {
            boolean adaptiveRefPicMarkingModeFlag = readBool(_in, "SH: adaptive_ref_pic_marking_mode_flag");
            if (adaptiveRefPicMarkingModeFlag) {
                ArrayList<Instruction> mmops = new ArrayList<Instruction>();
                int memoryManagementControlOperation;
                do {
                    memoryManagementControlOperation = readUEtrace(_in, "SH: memory_management_control_operation");

                    Instruction instr = null;

                    switch (memoryManagementControlOperation) {
                    case 1:
                        instr = new RefPicMarking.Instruction(InstrType.REMOVE_SHORT, readUEtrace(_in,
                                "SH: difference_of_pic_nums_minus1") + 1, 0);
                        break;
                    case 2:
                        instr = new RefPicMarking.Instruction(InstrType.REMOVE_LONG,
                                readUEtrace(_in, "SH: long_term_pic_num"), 0);
                        break;
                    case 3:
                        instr = new RefPicMarking.Instruction(InstrType.CONVERT_INTO_LONG, readUEtrace(_in,
                                "SH: difference_of_pic_nums_minus1") + 1, readUEtrace(_in, "SH: long_term_frame_idx"));
                        break;
                    case 4:
                        instr = new RefPicMarking.Instruction(InstrType.TRUNK_LONG, readUEtrace(_in,
                                "SH: max_long_term_frame_idx_plus1") - 1, 0);
                        break;
                    case 5:
                        instr = new RefPicMarking.Instruction(InstrType.CLEAR, 0, 0);
                        break;
                    case 6:
                        instr = new RefPicMarking.Instruction(InstrType.MARK_LONG,
                                readUEtrace(_in, "SH: long_term_frame_idx"), 0);
                        break;
                    }
                    if (instr != null)
                        mmops.add(instr);
                } while (memoryManagementControlOperation != 0);
                sh.refPicMarkingNonIDR = new RefPicMarking(mmops.toArray(new Instruction[] {}));
            }
        }
    }


public static Pair<List<Edit>> split(MovieBox movie, TrakBox track, long tvMv) {
        return splitEdits(track.getEdits(), new Rational(track.getTimescale(), movie.getTimescale()), tvMv);
    }

public static Pair < List < Edit > > split ( MovieBox movie , TrakBox track , long tvMv ) { return splitEdits ( track . getEdits ( ) , new Rational ( track . getTimescale ( ) , movie . getTimescale ( ) ) , tvMv ) ; }

Splits track on the timevalue specified

@param movie
@param track
@param tvMv
@return


public void decodeFrame(byte[] frame, SampleBuffer buffer) throws AACException {
        if (frame != null)
            _in.setData(frame);
        Logger.debug("bits left " + _in.getBitsLeft());
        try {
            decode(buffer);
        } catch (AACException e) {
            if (!e.isEndOfStream())
                throw e;
            else
                Logger.warn("unexpected end of frame");
        }
    }

public
void
decodeFrame
(
byte
[
]
frame
,
SampleBuffer
buffer
)
throws
AACException
{
if
(
frame
!=
)
_in
.
setData
(
frame
)
;
Logger
.
debug
(
"bits left "
+
_in
.
getBitsLeft
(
)
)
;
try
{
decode
(
buffer
)
;
}
catch
(
AACException
e
)
{
if
(
!
e
.
isEndOfStream
(
)
)
throw
e
;
else
Logger
.
warn
(
"unexpected end of frame"
)
;
}
}

Decodes one frame of AAC data in frame mode and returns the raw PCM data.

@param frame
the AAC frame
@param buffer
a buffer to hold the decoded PCM data
@throws AACException
if decoding fails

Decodes one frame of AAC data in frame mode and returns the raw PCM data .


public void setBigEndian(boolean bigEndian) {
		if(bigEndian!=this.bigEndian) {
			byte tmp;
			for(int i = 0; i<data.length; i += 2) {
				tmp = data[i];
				data[i] = data[i+1];
				data[i+1] = tmp;
			}
			this.bigEndian = bigEndian;
		}
	}

public void setBigEndian ( boolean bigEndian ) { if ( bigEndian != this . bigEndian ) { byte tmp ; for ( int i = 0 ; i < data . length ; i += 2 ) { tmp = data [ i ] ; data [ i ] = data [ i + 1 ] ; data [ i + 1 ] = tmp ; } this . bigEndian = bigEndian ; } }

Sets the endianness for the data.

@param bigEndian if true the data will be in big endian, else in little
endian


public void deblockMBP(EncodedMB cur, EncodedMB left, EncodedMB top) {
        int[][] vertStrength = new int[4][4];
        int[][] horizStrength = new int[4][4];

        calcStrengthForBlocks(cur, left, vertStrength, LOOKUP_IDX_P_V, LOOKUP_IDX_Q_V);
        calcStrengthForBlocks(cur, top, horizStrength, LOOKUP_IDX_P_H, LOOKUP_IDX_Q_H);

        deblockMBGeneric(cur, left, top, vertStrength, horizStrength);
    }

public void deblockMBP ( EncodedMB cur , EncodedMB left , EncodedMB top ) { int [ ] [ ] vertStrength = new int [ 4 ] [ 4 ] ; int [ ] [ ] horizStrength = new int [ 4 ] [ 4 ] ; calcStrengthForBlocks ( cur , left , vertStrength , LOOKUP_IDX_P_V , LOOKUP_IDX_Q_V ) ; calcStrengthForBlocks ( cur , top , horizStrength , LOOKUP_IDX_P_H , LOOKUP_IDX_Q_H ) ; deblockMBGeneric ( cur , left , top , vertStrength , horizStrength ) ; }

Deblocks P-macroblock

@param cur
Pixels and parameters of encoded and reconstructed current
macroblock
@param left
Pixels and parameters of encoded and reconstructed left
macroblock
@param top
Pixels and parameters of encoded and reconstructed top
macroblock


public void encodeNativeFrame(Picture pic) throws IOException {
		if (pic.getColor() != ColorSpace.RGB)
			throw new IllegalArgumentException("The input images is expected in RGB color.");

		ColorSpace sinkColor = sink.getInputColor();
		LoanerPicture toEncode;
		if (sinkColor != null) {
			toEncode = pixelStore.getPicture(pic.getWidth(), pic.getHeight(), sinkColor);
			transform.transform(pic, toEncode.getPicture());
		} else {
			toEncode = new LoanerPicture(pic, 0);
		}

		Packet pkt = Packet.createPacket(null, timestamp, fps.getNum(), fps.getDen(), frameNo, FrameType.KEY, null);
		sink.outputVideoFrame(new VideoFrameWithPacket(pkt, toEncode));

		if (sinkColor != null)
			pixelStore.putBack(toEncode);

		timestamp += fps.getDen();
		frameNo++;
	}

Encodes a frame into a movie.

@param pic
@throws IOException


public static byte[] ebmlEncodeLen(long value, int length) {
        byte[] b = new byte[length];
        for (int idx = 0; idx < length; idx++) {
            // Rightmost bytes should go to end of array to preserve big-endian notation
            b[length - idx - 1] = (byte) ((value >>> (8 * idx)) & 0xFFL);
        }

        b[0] |= 0x80 >>> (length - 1);
        return b;
    }

Encodes unsigned integer with given length

@param value
unsigned integer to be encoded
@param length
ebml sequence length
@return


public static int ebmlLength(long v) {
        if (v == 0)
            return 1;

        int length = 8;

        while (length > 0 && (v & ebmlLengthMasks[length]) == 0)
            length--;

        return length;
    }

public static int ebmlLength ( long v ) { if ( v == 0 ) return 1 ; int length = 8 ; while ( length > 0 && ( v & ebmlLengthMasks [ length ] ) == 0 ) length -- ; return length ; }

This method is used mostly during writing EBML bitstream. It answers the following question "How many bytes should be used to encode unsigned integer value"

@param v
unsigned integer to be encoded
@return

This method is used mostly during writing EBML bitstream . It answers the following question How many bytes should be used to encode unsigned integer value


public void addPacket(FLVTag pkt) throws IOException {
        if (!writePacket(writeBuf, pkt)) {
            writeBuf.flip();
            startOfLastPacket -= out.write(writeBuf);
            writeBuf.clear();
            if (!writePacket(writeBuf, pkt))
                throw new RuntimeException("Unexpected");
        }
    }

public void addPacket ( FLVTag pkt ) throws IOException { if ( ! writePacket ( writeBuf , pkt ) ) { writeBuf . flip ( ) ; startOfLastPacket -= out . write ( writeBuf ) ; writeBuf . clear ( ) ; if ( ! writePacket ( writeBuf , pkt ) ) throw new RuntimeException ( "Unexpected" ) ; } }

Add a packet to the underlying file

@param pkt
@throws IOException


public boolean repositionFile() throws IOException {
        int payloadSize = 0;
        for (int i = 0; i < REPOSITION_BUFFER_READS; i++) {
            while (readBuf.hasRemaining()) {
                payloadSize = ((payloadSize & 0xffff) << 8) | (readBuf.get() & 0xff);
                int pointerPos = readBuf.position() + 7 + payloadSize;
                if (readBuf.position() >= 8 && pointerPos < readBuf.limit() - 4
                        && readBuf.getInt(pointerPos) - payloadSize == 11) {
                    readBuf.position(readBuf.position() - 8);
                    return true;
                }
            }
            initialRead(ch);
            if (!readBuf.hasRemaining())
                break;
        }
        return false;
    }

public boolean repositionFile ( ) throws IOException { int payloadSize = 0 ; for ( int i = 0 ; i < REPOSITION_BUFFER_READS ; i ++ ) { while ( readBuf . hasRemaining ( ) ) { payloadSize = ( ( payloadSize & 0xffff ) << 8 ) | ( readBuf . get ( ) & 0xff ) ; int pointerPos = readBuf . position ( ) + 7 + payloadSize ; if ( readBuf . position ( ) >= 8 && pointerPos < readBuf . limit ( ) - 4 && readBuf . getInt ( pointerPos ) - payloadSize == 11 ) { readBuf . position ( readBuf . position ( ) - 8 ) ; return true ; } } initialRead ( ch ) ; if ( ! readBuf . hasRemaining ( ) ) break ; } return false ; }

Searching for the next tag in a file after corrupt segment

@return
@throws IOException


public int decodeBin(int m) {
        int bin;

        int qIdx = (range >> 6) & 0x3;
        int rLPS = MConst.rangeLPS[qIdx][cm[0][m]];
        range -= rLPS;
        int rs8 = range << 8;

        if (code < rs8) {
            // MPS
            if (cm[0][m] < 62)
                cm[0][m]++;

            renormalize();

            bin = cm[1][m];
        } else {
            // LPS
            range = rLPS;
            code -= rs8;

            renormalize();

            bin = 1 - cm[1][m];

            if (cm[0][m] == 0)
                cm[1][m] = 1 - cm[1][m];

            cm[0][m] = MConst.transitLPS[cm[0][m]];
        }

//        System.out.println("CABAC BIT [" + m + "]: " + bin);
        return bin;
    }

Decodes one bin from arithmetice code word

@param cm
@return
@throws IOException


public int decodeBinBypass() {
        code <<= 1;

        --nBitsPending;
        if (nBitsPending <= 0)
            readOneByte();

        int tmp = code - (range << 8);
        if (tmp < 0) {
//            System.out.println("CABAC BIT [-1]: 0");
            return 0;
        } else {
//            System.out.println("CABAC BIT [-1]: 1");
            code = tmp;
            return 1;
        }
    }

Special decoding process for symbols with uniform distribution

@return
@throws IOException


public static final ByteBuffer gotoMarker(ByteBuffer buf, int n, int mmin, int mmax) {
        if (!buf.hasRemaining())
            return null;

        int from = buf.position();
        ByteBuffer result = buf.slice();
        result.order(ByteOrder.BIG_ENDIAN);

        int val = 0xffffffff;
        while (buf.hasRemaining()) {
            val = (val << 8) | (buf.get() & 0xff);
            if (val >= mmin && val <= mmax) {
                if (n == 0) {
                    buf.position(buf.position() - 4);
                    result.limit(buf.position() - from);
                    break;
                }
                --n;
            }
        }
        return result;
    }

public static final ByteBuffer gotoMarker ( ByteBuffer buf , int n , int mmin , int mmax ) { if ( ! buf . hasRemaining ( ) ) return null ; int from = buf . position ( ) ; ByteBuffer result = buf . slice ( ) ; result . order ( ByteOrder . BIG_ENDIAN ) ; int val = 0xffffffff ; while ( buf . hasRemaining ( ) ) { val = ( val << 8 ) | ( buf . get ( ) & 0xff ) ; if ( val >= mmin && val <= mmax ) { if ( n == 0 ) { buf . position ( buf . position ( ) - 4 ) ; result . limit ( buf . position ( ) - from ) ; break ; } -- n ; } } return result ; }

Finds next Nth MPEG bitstream marker 0x000001xx and returns the data that
preceeds it as a ByteBuffer slice

Segment byte order is always little endian

@param buf
@return


public static SampleFrequency forInt(int i) {
        final SampleFrequency freq;
        if (i >= 0 && i < 12)
            freq = values()[i];
        else
            freq = SAMPLE_FREQUENCY_NONE;
        return freq;
    }

public static SampleFrequency forInt ( int i ) { final SampleFrequency freq ; if ( i >= 0 && i < 12 ) freq = values ( ) [ i ] ; else freq = SAMPLE_FREQUENCY_NONE ; return freq ; }

Returns a sample frequency instance for the given index. If the index is
not between 0 and 11 inclusive, SAMPLE_FREQUENCY_NONE is returned.

@return a sample frequency with the given index

Returns a sample frequency instance for the given index . If the index is not between 0 and 11 inclusive SAMPLE_FREQUENCY_NONE is returned .


@Override
    public void predictPlane(byte[] ref, int refX, int refY, int refW, int refH, int refVertStep, int refVertOff,
            int[] tgt, int tgtY, int tgtW, int tgtH, int tgtVertStep) {
        super.predictPlane(ref, refX << 1, refY << 1, refW, refH, refVertStep, refVertOff, tgt, tgtY, tgtW << 2, tgtH << 2,
                tgtVertStep);
    }

@ Override public void predictPlane ( byte [ ] ref , int refX , int refY , int refW , int refH , int refVertStep , int refVertOff , int [ ] tgt , int tgtY , int tgtW , int tgtH , int tgtVertStep ) { super . predictPlane ( ref , refX << 1 , refY << 1 , refW , refH , refVertStep , refVertOff , tgt , tgtY , tgtW << 2 , tgtH << 2 , tgtVertStep ) ; }

this may be a result of color greening out in long GOPs.

this may be a result of color greening out in long GOPs .


public static final void start(int[] block, int dc) {
        dc <<= DC_SHIFT;
        for (int i = 0; i < 64; i += 4) {
            block[i + 0] = dc;
            block[i + 1] = dc;
            block[i + 2] = dc;
            block[i + 3] = dc;
        }
    }

public static final void start ( int [ ] block , int dc ) { dc <<= DC_SHIFT ; for ( int i = 0 ; i < 64 ; i += 4 ) { block [ i + 0 ] = dc ; block [ i + 1 ] = dc ; block [ i + 2 ] = dc ; block [ i + 3 ] = dc ; } }

Starts DCT reconstruction

Faster then call to 'coeff' with ind = 0

@param block
@param dc


public static final void coeff(int[] block, int ind, int level) {
        for (int i = 0; i < 64; i += 4) {
            block[i] += COEFF[ind][i] * level;
            block[i + 1] += COEFF[ind][i + 1] * level;
            block[i + 2] += COEFF[ind][i + 2] * level;
            block[i + 3] += COEFF[ind][i + 3] * level;
        }
    }

public static final void coeff ( int [ ] block , int ind , int level ) { for ( int i = 0 ; i < 64 ; i += 4 ) { block [ i ] += COEFF [ ind ] [ i ] * level ; block [ i + 1 ] += COEFF [ ind ] [ i + 1 ] * level ; block [ i + 2 ] += COEFF [ ind ] [ i + 2 ] * level ; block [ i + 3 ] += COEFF [ ind ] [ i + 3 ] * level ; } }

Recalculates image based on new DCT coefficient

@param block
@param ind
@param level


public static final void finish(int block[]) {
        for (int i = 0; i < 64; i += 4) {
            block[i] = div(block[i]);
            block[i + 1] = div(block[i + 1]);
            block[i + 2] = div(block[i + 2]);
            block[i + 3] = div(block[i + 3]);
        }
    }

public static final void finish ( int block [ ] ) { for ( int i = 0 ; i < 64 ; i += 4 ) { block [ i ] = div ( block [ i ] ) ; block [ i + 1 ] = div ( block [ i + 1 ] ) ; block [ i + 2 ] = div ( block [ i + 2 ] ) ; block [ i + 3 ] = div ( block [ i + 3 ] ) ; } }


public void concatBits(BitsBuffer a) {
		if(a.len==0) return;
		int al = a.bufa;
		int ah = a.bufb;

		int bl, bh;
		if(len>32) {
			//mask off superfluous high b bits
			bl = bufa;
			bh = bufb&((1<<(len-32))-1);
			//left shift a len bits
			ah = al<<(len-32);
			al = 0;
		}
		else {
			bl = bufa&((1<<(len))-1);
			bh = 0;
			ah = (ah<<(len))|(al>>(32-len));
			al = al<<len;
		}

		//merge
		bufa = bl|al;
		bufb = bh|ah;

		len += a.len;
	}

public
void
concatBits
(
BitsBuffer
a
)
{
if
(
a
.
len
==
0
)
return
;
int
al
=
a
.
bufa
;
int
ah
=
a
.
bufb
;
int
bl
,
bh
;
if
(
len
>
32
)
{
//mask off superfluous high b bits
bl
=
bufa
;
bh
=
bufb
&
(
(
1
<<
(
len
32
)
)
1
)
;
//left shift a len bits
ah
=
al
<<
(
len
32
)
;
al
=
0
;
}
else
{
bl
=
bufa
&
(
(
1
<<
(
len
)
)
1
)
;
bh
=
0
;
ah
=
(
ah
<<
(
len
)
)
|
(
al
>>
(
32
len
)
)
;
al
=
al
<<
len
;
}
//merge
bufa
=
bl
|
al
;
bufb
=
bh
|
ah
;
len
+=
a
.
len
;
}


protected int seekToKeyFrame(int frame) throws IOException {
        if (videoInputTrack instanceof SeekableDemuxerTrack) {
            SeekableDemuxerTrack seekable = (SeekableDemuxerTrack) videoInputTrack;
            seekable.gotoSyncFrame(frame);
            return (int) seekable.getCurFrame();
        } else {
            Logger.warn("Can not seek in " + videoInputTrack + " container.");
            return -1;
        }
    }

protected
int
seekToKeyFrame
(
int
frame
)
throws
IOException
{
if
(
videoInputTrack
instanceof
SeekableDemuxerTrack
)
{
SeekableDemuxerTrack
seekable
=
(
SeekableDemuxerTrack
)
videoInputTrack
;
seekable
.
gotoSyncFrame
(
frame
)
;
return
(
int
)
seekable
.
getCurFrame
(
)
;
}
else
{
Logger
.
warn
(
"Can not seek in "
+
videoInputTrack
+
" container."
)
;
return
1
;
}
}

Seeks to a previous key frame prior or on the given frame, if the track is
not seekable returns 0.

@param frame
A frame to seek
@return Frame number of a key frame or 0 if the track is not seekable.
@throws IOException

Seeks to a previous key frame prior or on the given frame if the track is not seekable returns 0 .


protected LoanerPicture getPixelBuffer(ByteBuffer firstFrame) {
        VideoCodecMeta videoMeta = getVideoCodecMeta();
        Size size = videoMeta.getSize();
        return pixelStore.getPicture((size.getWidth() + 15) & ~0xf, (size.getHeight() + 15) & ~0xf,
                videoMeta.getColor());
    }

protected LoanerPicture getPixelBuffer ( ByteBuffer firstFrame ) { VideoCodecMeta videoMeta = getVideoCodecMeta ( ) ; Size size = videoMeta . getSize ( ) ; return pixelStore . getPicture ( ( size . getWidth ( ) + 15 ) & ~ 0xf , ( size . getHeight ( ) + 15 ) & ~ 0xf , videoMeta . getColor ( ) ) ; }

Returns a pixel buffer of a suitable size to hold the given video frame. The
video size is taken either from the video metadata or by analyzing the
incoming video packet.

@param firstFrame
@return

Returns a pixel buffer of a suitable size to hold the given video frame . The video size is taken either from the video metadata or by analyzing the incoming video packet .


private int getGainChangePointID(int lngain) {
		for(int i = 0; i<ID_GAIN; i++) {
			if(lngain==LN_GAIN[i]) return i;
		}
		return 0; //shouldn't happen
	}

private
int
getGainChangePointID
(
int
lngain
)
{
for
(
int
i
=
0
;
i
<
ID_GAIN
;
i
++
)
{
if
(
lngain
==
LN_GAIN
[
i
]
)
return
i
;
}
return
0
;
//shouldn't happen
}

transformes the exponent value of the gain to the id of the gain change
point


public static int[] fromByte(byte[] b, int depth, boolean isBe) {
        if (depth == 24)
            if (isBe)
                return from24BE(b);
            else
                return from24LE(b);
        else if (depth == 16)
            if (isBe)
                return from16BE(b);
            else
                return from16LE(b);
        throw new NotSupportedException("Conversion from " + depth + "bit "
                + (isBe ? "big endian" : "little endian") + " is not supported.");
    }

public
static
int
[
]
fromByte
(
byte
[
]
b
,
int
depth
,
boolean
isBe
)
{
if
(
depth
==
24
)
if
(
isBe
)
return
from24BE
(
b
)
;
else
return
from24LE
(
b
)
;
else
if
(
depth
==
16
)
if
(
isBe
)
return
from16BE
(
b
)
;
else
return
from16LE
(
b
)
;
throw
new
NotSupportedException
(
"Conversion from "
+
depth
+
"bit "
+
(
isBe
"big endian"
:
"little endian"
)
+
" is not supported."
)
;
}

Generic byte-array to integer-array conversion

Converts each depth-bit sequence from the input byte array into integer

@param b
Input bytes
@param depth
Bit depth of the integers
@param isBe
If integers are big-endian or little-endian
@return

Generic byte - array to integer - array conversion


public static byte[] toByte(int[] ia, int depth, boolean isBe) {
        if (depth == 24)
            if (isBe)
                return to24BE(ia);
            else
                return to24LE(ia);
        else if (depth == 16)
            if (isBe)
                return to16BE(ia);
            else
                return to16LE(ia);
        throw new NotSupportedException("Conversion to " + depth + "bit " + (isBe ? "big endian" : "little endian")
                + " is not supported.");
    }

public
static
byte
[
]
toByte
(
int
[
]
ia
,
int
depth
,
boolean
isBe
)
{
if
(
depth
==
24
)
if
(
isBe
)
return
to24BE
(
ia
)
;
else
return
to24LE
(
ia
)
;
else
if
(
depth
==
16
)
if
(
isBe
)
return
to16BE
(
ia
)
;
else
return
to16LE
(
ia
)
;
throw
new
NotSupportedException
(
"Conversion to "
+
depth
+
"bit "
+
(
isBe
"big endian"
:
"little endian"
)
+
" is not supported."
)
;
}

Generic integer-array to byte-array conversion

Converts each integer into depth-bit sequence in the output byte array

@param ia
Integer array
@param depth
Bit depth of the integers
@param isBe
If integers are big-endian or little-endian
@return

Generic integer - array to byte - array conversion


public static void toFloat(AudioFormat format, ByteBuffer buf, FloatBuffer floatBuf) {
        if (!format.isSigned())
            throw new NotSupportedException("Unsigned PCM is not supported ( yet? ).");

        if (format.getSampleSizeInBits() != 16 && format.getSampleSizeInBits() != 24)
            throw new NotSupportedException(format.getSampleSizeInBits() + " bit PCM is not supported ( yet? ).");

        if (format.isBigEndian()) {
            if (format.getSampleSizeInBits() == 16) {
                toFloat16BE(buf, floatBuf);
            } else {
                toFloat24BE(buf, floatBuf);
            }
        } else {
            if (format.getSampleSizeInBits() == 16) {
                toFloat16LE(buf, floatBuf);
            } else {
                toFloat24LE(buf, floatBuf);
            }
        }
    }

Converts PCM samples stored in buf and described with format to float
array representation

@param format
Supported formats - *_*_S16_LE, *_*_S24_LE, *_*_S16_BE,
*_*_S24_LE
@param buf
@param floatBuf
@return Total number of samples read from the buffer


public static void fromFloat(FloatBuffer floatBuf, AudioFormat format, ByteBuffer buf) {
        if (!format.isSigned())
            throw new NotSupportedException("Unsigned PCM is not supported ( yet? ).");

        if (format.getSampleSizeInBits() != 16 && format.getSampleSizeInBits() != 24)
            throw new NotSupportedException(format.getSampleSizeInBits() + " bit PCM is not supported ( yet? ).");

        if (format.isBigEndian()) {
            if (format.getSampleSizeInBits() == 16) {
                fromFloat16BE(buf, floatBuf);
            } else {
                fromFloat24BE(buf, floatBuf);
            }
        } else {
            if (format.getSampleSizeInBits() == 16) {
                fromFloat16LE(buf, floatBuf);
            } else {
                fromFloat24LE(buf, floatBuf);
            }
        }
    }

Converts float PCM samples stored in floatBuf to integer representation
according to format and stores them in buf

@param format
Supported formats - *_*_S16_LE, *_*_S24_LE, *_*_S16_BE,
*_*_S24_LE
@param buf
@param floatBuf
@return Total number of samples written to the buffer


public static void interleave(AudioFormat format, ByteBuffer[] ins, ByteBuffer outb) {
        int bytesPerSample = format.getSampleSizeInBits() >> 3;
        int bytesPerFrame = bytesPerSample * ins.length;

        int max = 0;
        for (int i = 0; i < ins.length; i++)
            if (ins[i].remaining() > max)
                max = ins[i].remaining();

        for (int frames = 0; frames < max && outb.remaining() >= bytesPerFrame; frames++) {
            for (int j = 0; j < ins.length; j++) {
                if (ins[j].remaining() < bytesPerSample) {
                    for (int i = 0; i < bytesPerSample; i++)
                        outb.put((byte) 0);
                } else {
                    for (int i = 0; i < bytesPerSample; i++) {
                        outb.put(ins[j].get());
                    }
                }
            }
        }
    }

public static void interleave ( AudioFormat format , ByteBuffer [ ] ins , ByteBuffer outb ) { int bytesPerSample = format . getSampleSizeInBits ( ) >> 3 ; int bytesPerFrame = bytesPerSample * ins . length ; int max = 0 ; for ( int i = 0 ; i < ins . length ; i ++ ) if ( ins [ i ] . remaining ( ) > max ) max = ins [ i ] . remaining ( ) ; for ( int frames = 0 ; frames < max && outb . remaining ( ) >= bytesPerFrame ; frames ++ ) { for ( int j = 0 ; j < ins . length ; j ++ ) { if ( ins [ j ] . remaining ( ) < bytesPerSample ) { for ( int i = 0 ; i < bytesPerSample ; i ++ ) outb . put ( ( byte ) 0 ) ; } else { for ( int i = 0 ; i < bytesPerSample ; i ++ ) { outb . put ( ins [ j ] . get ( ) ) ; } } } } }

Interleaves audio samples in ins into outb using sample size from the
format

@param format
@param ins
@param outb


public static void deinterleave(AudioFormat format, ByteBuffer inb, ByteBuffer[] outs) {
        int bytesPerSample = format.getSampleSizeInBits() >> 3;
        int bytesPerFrame = bytesPerSample * outs.length;

        while (inb.remaining() >= bytesPerFrame) {
            for (int j = 0; j < outs.length; j++) {
                for (int i = 0; i < bytesPerSample; i++) {
                    outs[j].put(inb.get());
                }
            }
        }
    }

public static void deinterleave ( AudioFormat format , ByteBuffer inb , ByteBuffer [ ] outs ) { int bytesPerSample = format . getSampleSizeInBits ( ) >> 3 ; int bytesPerFrame = bytesPerSample * outs . length ; while ( inb . remaining ( ) >= bytesPerFrame ) { for ( int j = 0 ; j < outs . length ; j ++ ) { for ( int i = 0 ; i < bytesPerSample ; i ++ ) { outs [ j ] . put ( inb . get ( ) ) ; } } } }

Deinterleaves audio samples from inb into outs using sample size from
format

@param format
@param inb
@param outs


public Size getCodedSize() {
        SampleEntry se = getSampleEntries()[0];
        if (!(se instanceof VideoSampleEntry))
            throw new IllegalArgumentException("Not a video track");
        VideoSampleEntry vse = (VideoSampleEntry) se;

        return new Size(vse.getWidth(), vse.getHeight());
    }

public
Size
getCodedSize
(
)
{
SampleEntry
se
=
getSampleEntries
(
)
[
0
]
;
if
(
!
(
se
instanceof
VideoSampleEntry
)
)
throw
new
IllegalArgumentException
(
"Not a video track"
)
;
VideoSampleEntry
vse
=
(
VideoSampleEntry
)
se
;
return
new
Size
(
vse
.
getWidth
(
)
,
vse
.
getHeight
(
)
)
;
}

Retrieves coded size of this video track.

Note: May be different from video display dimension.

@return

Retrieves coded size of this video track .